前端笔试遇到的两个编程题

Posted moxiaozhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端笔试遇到的两个编程题相关的知识,希望对你有一定的参考价值。

倒计时:

在倒计时不超过一天的代码

var hour = document.querySelector(".hour");
    var minute = document.querySelector(".minute");
    var second = document.querySelector(".second");
//截止的时间
    var inputTime = +new Date("2023-4-08 20:00:00 ");
//我们先调用countDown函数,可以避免在打开界面后停一秒后才开始倒计时
    countDown();
    setInterval(countDown, 1000);

    function countDown()
      var nowTime = +new Date();
      var times = (inputTime - nowTime) / 1000;
      var h = parseInt((times / 60 / 60) % 24);
      var m = parseInt((times / 60) % 60);
      var s = parseInt(times % 60);
      hour.innerHTML = h < 10 ? "0" + h : h;
      minute.innerHTML = m < 10 ? "0" + m : m;
      second.innerHTML = s < 10 ? "0" + s : s;
   
 
天数的那种:
var day=document.querySelector(".day")
var hour = document.querySelector(".hour");
    var minute = document.querySelector(".minute");
    var second = document.querySelector(".second");
//截止的时间
    var inputTime = +new Date("2023-4-08 20:00:00 ");
//我们先调用countDown函数,可以避免在打开界面后停一秒后才开始倒计时
    countDown();
    setInterval(countDown, 1000);

    function countDown()
      var nowTime = +new Date();
      var times = (inputTime - nowTime) / 1000;
  var h=parseInt(times/60/60/24)
      var h = parseInt((times / 60 / 60) % 24);
      var m = parseInt((times / 60) % 60);
      var s = parseInt(times % 60);
      hour.innerHTML = h < 10 ? "0" + h : h;
      minute.innerHTML = m < 10 ? "0" + m : m;
      second.innerHTML = s < 10 ? "0" + s : s;
   day.innerHTML = d < 10 ? "0" + d : d;
   
 
取url

 

 

  const url =
        "https://www.baidu.com/m?f=8&ie=utf-8&rsv_bp=1&tn=monline_3_dg&wd=session";
function queryURLparams(url)
      let obj = ;
      if (url.indexOf("?") < 0) return obj;
      let arr = url.split("?");
      let urlcopy = arr[1];
      let array = urlcopy.split("&");
      for (var i = 0; i < array.length; i++)
        let arr2 = array[i];
        let arr3 = arr2.split("=");
        obj[arr3[0]] = arr3[1];
     
      return obj
  • 正则匹配规则 /([^?=&]+)=([^?=&]+)/g
  • 利用replace替换
  • 用伪数组进行键值对拼接
function queryURLparamsReg(url)
  let obj=
  let reg=/([^?=&]+)=([^?=&]+)/g
url.replace(reg,function()
obj[arguments[1]]=arguments[2]
)
return obj

es6的 …arg

其实和arguments差不多 ,就是arguments是伪数组,…arg是真数组

function queryURLparamsRegEs6(url)
let obj =
let reg = /([^?=&]+)=([^?=&]+)/g
url.replace(reg, (...arg) =>
obj[arg[1]] = arg[2]
)
return obj



2021年中级前端笔试面试题总结(含答案解析)

记录本人在广州面试中遇到的一些问题(主要是技术一面),公司中小企业居多,也有大厂(非BAT)。岗位一般写的中级前端开发或1~3年经验岗位。问题主要选取一些高频和基础的问题。(问题的回答只是本人的理解,非参考答案,有些答案只给个提示,详解可谷歌百度或在掘金内搜索相关文章)

题目

  • 考察频率指相关问题的考察频率,并非只是提到的点。

JavaScript基础

1、声明提升类问题 (考察频率:高)

变量声明和函数声明都会提升,但函数会提升到变量前。 具体解释可参考《你不知道的JavaScript(上卷)》

2、js存储方式(考察频率:中)

  • cookie
  • sessionStorage
  • localStorage
  • indexedDB

3、什么情况下会遇到跨域,怎么解决?(考察频率:高)

  • 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。若地址里面的协议、域名和端口号均相同则属于同源。
  • jsonp跨域、nginx反向代理、node.js中间件代理跨域、后端设置http header、后端在服务器上设置cors。

4、Promise中的执行顺序(考察频率:高)

参考阮一峰老师书中的例子

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

5、JavaScript事件循环机制相关问题(考察频率:高)

  • 事件循环机制的概念

关键字:单线程非阻塞、执行栈、事件队列、宏任务(setTimeout()、setInterval())、微任务(new Promise())

可参考: zhuanlan.zhihu.com/p/33058983

  • 宏任务、微任务、同步任务的执行顺序
setTimeout(function () {
    console.log(1);
});

new Promise(function(resolve,reject){
    console.log(2)
    resolve(3)
}).then(function(val){
    console.log(val);
})
console.log(4);
// 2
// 4
// 3
// 1

先按顺序执行同步任务,Promise新建后立即执行输出2,接着输出4,异步任务等同步任务执行完后执行,且同一次事件循环中,微任务永远在宏任务之前执行。这时候执行栈空了,执行事件队列,先取出微任务,输出3,最后取出一个宏任务,输出1。

6、for循环中的作用域问题(考察频率:高)

写出以下代码输出值,尝试用es5和es6的方式进行改进输出循环中的i值。

for (var i=1; i<=5; i++) { 
    setTimeout(function timer() { 
       console.log(i); 
    }, i*1000); 
}
  • 输出5个6,因为回调函数在for循环之后执行,所有函数共享一个i的引用。
  • es5:
for (var i=1; i<=5; i++) { 
    (function(j) { 
        setTimeout(function timer() { 
            console.log(j); 
        }, j*1000); 
    })(i); 
}

  • es6:
for (let i=1; i<=5; i++) { 
    setTimeout(function timer() { 
        console.log(i);
    }, i*1000); 
}

7、闭包的作用(考察频率:中)

闭包的目的是外部函数可以访问内部函数的作用域(局部作用域)。比如访问到内部作用域的变量。

8、原型及原型链(考察频率:中)

原型的理解

  • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null除外)
  • 所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通的对象
  • 所有的函数,都有一个prototype属性,属性值也是一个普通的对象
  • 所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值

原型链的理解

一段代码如下:

// 构造函数
function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function () {
    alert(this.name)
}
// 创建示例
var f = new Foo('zhangsan')
f.printName = function () {
    console.log(this.name)
}
// 测试
f.printName()
f.alertName()
f.toString()

因为f本身没有toString(),并且f.proto(即Foo.prototype)中也没有toString。当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。

如果在f.__proto__中没有找到toString,那么就继续去f.proto.__proto__中寻找,因为f.__proto__就是一个普通的对象而已嘛!

f.__proto__即Foo.prototype,没有找到toString,继续往上找 f.proto.__proto__即Foo.prototype.proto。Foo.prototype就是一个普通的对象,因此Foo.prototype.__proto__就是Object.prototype,在这里可以找到toString。 因此f.toString最终对应到了Object.prototype.toString 这样一直往上找,你会发现是一个链式的结构,所以叫做“原型链”。如果一直找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 —— Object.prototype.proto === null

9、重绘和回流(考察频率:中)

  • 重绘:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
  • 回流:当Render Tree(DOM)中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
  • 回流要比重绘消耗性能开支更大。
  • 回流必将引起重绘,重绘不一定会引起回流。
  • 参考:juejin.im/post/684490…

10、实现一个深拷贝(思路)(考察频率:中)

对象中可能又存在对象,所以需要深拷贝。首先需要知道这是一个递归调用,然后要判断一些特殊类型(数组,正则对象,函数)进行具体的操作,可以通过Object.prototype.toString.call(obj)进行判断。

11、js浮点数运算精度问题(0.1+0.2!==0.3)

比如在 JavaScript 中计算 0.1 + 0.2时,到底发生了什么呢?

首先,十进制的0.1和0.2都会被转换成二进制,但由于浮点数用二进制表达时是无穷的,例如。

JavaScript 代码:
0.1 -> 0.0001100110011001…(无限)
0.2 -> 0.0011001100110011…(无限)
IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以两者相加之后得到二进制为:

JavaScript 代码: 0.0100110011001100110011001100110011001100110011001100
因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了 0.30000000000000004。所以在进行算术计算时会产生误差。

浏览器相关

12、浏览器从加载到渲染的过程,比如输入一个网址到显示页面的过程。 (考察频率:高)

加载过程:

  • 浏览器根据 DNS 服务器解析得到域名的 IP 地址
  • 向这个 IP 的机器发送 HTTP 请求
  • 服务器收到、处理并返回 HTTP 请求
  • 浏览器得到返回内容

渲染过程:

  • 根据 HTML 结构生成 DOM 树
  • 根据 CSS 生成 CSSOM
  • 将 DOM 和 CSSOM 整合形成 RenderTree
  • 根据 RenderTree 开始渲染和展示
  • 遇到

13、浏览器缓存机制(策略)(考察频率:中)

14、性能优化(考察频率:中)

优化的方向有两个:

  • 减少页面体积,提升网络加载
  • 优化页面渲染

减少页面体积,提升网络加载

  • 静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)
  • 静态资源缓存(资源名称加 MD5 戳)
  • 使用 CDN 让资源加载更快

优化页面渲染

  • CSS 放前面,JS 放后面
  • 懒加载(图片懒加载、下拉加载更多)
  • 减少DOM 查询,对 DOM 查询做缓存
  • 减少DOM 操作,多个操作尽量合并在一起执行(DocumentFragment)
  • 事件节流
  • 尽早执行操作(DOMContentLoaded)
  • 使用 SSR 后端渲染,数据直接输出到 HTML 中,减少浏览器使用 JS - 模板渲染页面 HTML 的时间

Vue

15、组件通信方式 (考察频率:高)

1)父->子

  • props(v-bind)

  • $refs

2)子->父

  • events(v-on)

  • $parent $root

3)非父子组件

  • event bus

  • vuex

16、双向绑定原理(考察频率:高)

网上各种文章很多,原理可以讲浅也可以讲深,看面试官自己的了解程度和他想考察的深度。 最基本的要讲清楚数据劫持Object.defineProperty(), 讲清楚依赖收集(Watcher、Dep)。

17、路由导航钩子(导航守卫)(考察频率:中)

  • 全局钩子
  • 路由独享钩子
  • 组件内钩子

看文档:router.vuejs.org/zh-cn/advan…

18、v-if和v-show的共同点和区别(考察频率:中)

参考官方文档

都是用来做条件渲染,通过条件控制元素的显示与隐藏。

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

19、说说vue的双向数据绑定实现原理(考察频率:中)

通过Object.definerProperty来劫持各个数据的属性的setter和getter,在数据变化时,发布消息给依赖收集器,通知观察者去执行回调函数,达到视图更新的效果。(但是使用Object.definerProperty实现监听时是有一些痛点的,比如,①无法监测数组下标变化,导致数组删除或者插入元素时,数组的变化无法实时响应;②只能对对象的属性进行监测,当对象深度比较深时,只能遍历每个属性来实现监听。vue3.0采用的Proxy,就完全避开了Object.definerProperty方法的这些痛点)

20、说一下vue的生命周期(考察频率:高)

beforeCreate:初始化事件,进行数据观测。

created:data数据进行绑定。

beforeMount:虚拟DOM替换真实DOM。

mounted:将DOM元素挂载到页面。

beforeUpdate: data数据更新之前。

updated: data数据更新完成之后。

beforeDestroy:在实例销毁之前调用,所有实例仍可以调用。

destroyed:在实例销毁之后调用,所有实例被销毁。

21、路由懒加载的作用

懒加载即在需要的时候才进行加载,随用随载。在单页面应用中,如果没有应用懒加载,webpack打包后的文件会非常大,导致第一次进入首页时,加载时间过长,不利于用户体验。而运用懒加载可以将页面进行划分,需要的时候才加载页面,可以有效的分担首页所承受的加载压力,有效减少了加载用时。

22、vue中如何监听数组的变化?

Object.definerProperty是无法对数组和对象进行劫持监听的,所以vue3.0以下(不包括3.0)版本,对数组的监听是直接重写了push、shift……等Array常用的数组操作。

总结

面试第一看眼缘,其次看实力,面试官觉得你自信,跟公司的岗位匹配,就会推荐你。

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。

为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

前端面试题汇总

JavaScript

性能

linux

前端资料汇总

完整版PDF资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了

前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。

以上是关于前端笔试遇到的两个编程题的主要内容,如果未能解决你的问题,请参考以下文章

去哪儿网2017校招在线笔试(前端工程师)编程题及JavaScript代码

西安尚学堂练习09.12|Java编程笔试面试题

58集团2017校招笔试-前端岗

小米2015笔试编程题

2021年中级前端笔试面试题总结(含答案解析)

2018年爱奇艺校招笔试