前言

哈,看样子年后跳槽还是大家比较关心的一件事情了,继第一波面试题汇总的反响和评论,观看和点赞的朋友们很多,我继续将后续面试的一些内容写出来,有很多面试题答案我自己写的比较含糊,但是在面试的过程中是描述的表较多的。毕竟写文字要写出来太多了。我也只是写了一个大概,如果对答案不太满意的同学可以自行查询标准答案哈。

2020 前端面试 | 第一波面试题总结

对了,有很多朋友说面试题过于简单都是基础之类的,实际上我本身也就是一个初中级的水平,所以面试的公司职位和对应的薪资匹配的就是这类的问题,算法题基本很少面试到。

薪资范围: 11k-14k

技术能力:自身能力强和扩展性高的可以自己跟HR多谈多要

面试建议:请勿态度高冷,聊天请等对方说完在回答,切勿抱怨和说上家公司的缺点

面试重点:JavaScript基础需要掌握得好,即使有些框架的原理和区别说不上来也没事

最后总结:本人还在面试中,如有贵公司在招聘初中级请联系我哈

面试题汇总

  • 请描述一下 React 和 Vue的区别

这道题你如果熟知的话,从各个方面的不同点,原理,为什么这样实现来描述,起吗聊个半个小时。后续就不会问你太多问题了。

1.设计思想
    vue的官网中说它是一款渐进式框架,采用自底向上增量开发的设计。
    
    react主张函数式编程,所以推崇纯组件,数据不可变,单向数据流,当然需要双向的地方也可以手动实现,
    比如借助 onChange 和 setState 来实现一个双向的数据流。
2.编写语法
    Vue推荐的做法是webpack+vue-loader的单文件组件格式,vue保留了html、css、js分离的写法
    
    React的开发者可能知道,react是没有模板的,直接就是一个渲染函数,它中间返回的就是一个虚拟DOM树,
    React推荐的做法是  JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即'all in  js'。
3.构建工具
    vue提供了CLI 脚手架,可以帮助你非常容易地构建项目。
    
    React 在这方面也提供了 create-react-app,但是现在还存在一些局限性,不能配置等等
4.数据绑定
    vue是实现了双向数据绑定的mvvm框架,当视图改变更新模型层,当模型层改变更新视图层。
    在vue中,使用了双向绑定技术,就是View的变化能实时让Model发生变化,而Model的变化也能实时更新到View。
    (这里我们可以继续深入讲解一下双向数据绑定的原理,我之前的文章手写Vue源码可参考)
    
    react是单向数据流,react中属性是不允许更改的,状态是允许更改的。
    react中组件不允许通过this.state这种方式直接更改组件的状态。自身设置的状态,可以通过setState来进行更改。
    (注意:React中setState是异步的,导致获取dom可能拿的还是之前的内容,
    所以我们需要在setState第二个参数(回调函数)中获取更新后的新的内容。)
    
    【这里如果你了解深入的话可以尝试描述一下React中setState的异步操作是怎么实现的,Vue中的更新是通过微任务等】
5.diff算法
    vue中diff算法实现流程:
        1.在内存中构建虚拟dom树
        2.将内存中虚拟dom树渲染成真实dom结构
        3.数据改变的时候,将之前的虚拟dom树结合新的数据生成新的虚拟dom树
        4.将此次生成好的虚拟dom树和上一次的虚拟dom树进行一次比对(diff算法进行比对),来更新只需要被替换的DOM,
        而不是全部重绘。在Diff算法中,只平层的比较前后两棵DOM树的节点,没有进行深度的遍历。
        5.会将对比出来的差异进行重新渲染
        
    react中diff算法实现流程:
        DOM结构发生改变-----直接卸载并重新create
        DOM结构一样-----不会卸载,但是会update变化的内容
        所有同一层级的子节点.他们都可以通过key来区分-----同时遵循1.2两点
        (其实这个key的存在与否只会影响diff算法的复杂度,换言之,你不加key的情况下,
        diff算法就会以暴力的方式去根据一二的策略更新,但是你加了key,diff算法会引入一些另外的操作)
    
复制代码

React会逐个对节点进行更新,转换到目标节点。而最后插入新的节点,涉及到的DOM操作非常多。diff总共就是移动、删除、增加三个操作,而如果给每个节点唯一的标识(key),那么React优先采用移动的方式,能够找到正确的位置去插入新的节点。

vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制。

以上内容来自于Vue 和 React 的优点分别是什么?,大家说的越多理解的越深越好。我只说了其中的三点。

  • 前端常用的数据请求格式有哪些?都有些什么特点?

这个问题在http中已经回答了一部分了,这里就在单独详细的描述一下使用场景

Get/Post/Delete/Patch/Put经常用的这五种,其他的就不说了

通常:
    我们使用Get请求来获取数据
    我们使用Post请求来发送数据
    我们使用Put请求来更新数据
    我们使用Delete请求来删除数据
    我们使用Patch请求用于对资源应用部分修改。
Get和Post的区别:
    1.Get 请求能缓存,Post 不能
    2.Post 相对 Get 安全一点点,因为Get 请求都包含在 URL 里,
    (当然你想写到 body 里也是可以的),且会被浏览器保存历史纪录。Post 不会,但是在抓包的情况下都是一样的。
    4.URL有长度限制,会影响 Get 请求,但是这个长度限制是浏览器规定的,不是 RFC 规定的
    5.Post 支持更多的编码类型且不对数据类型限制
复制代码
  • 二次封装axios,描述一下你在项目中封装axios的思路和想法
关于axios等封装,我之前有一篇简易封装axios的文章,大家可以简单参考。

通常来说,我们在二次封装axios,一般会引入UI组件的一些Message和Loading组件用来做提示信息。
    1.通过获取存储在浏览器端,或者是vuex中的token信息,判断是否跳转登录页面
    2.在获取到token的情况下设置自定义请求头部信息
    3.在响应事件中,根据返回的不同状态码,根据业务需求,使用switch判断跳转页面还是发出提示信息。
    4.封装请求和响应事件的返回结果,使用Promise封装。
    5.增加请求loading和提示信息。
简单版本大致如上,复杂版本需要根据业务进行对应的封装。
复制代码
  • 请介绍一下this
其实大部分情况下可以用一句话来概括,this总是指向调用该函数的对象。

对于常规的函数来说,谁调用该函数,this就指向该调用者,全局环境下调用函数执行,this指向window

对于箭头函数的this总结如下:

箭头函数不绑定this,箭头函数中的this相当于普通变量。

箭头函数的this寻值行为与普通变量相同,在作用域中逐级寻找。

箭头函数的this无法通过bind,call,apply来直接修改(可以间接修改)。

改变作用域中this的指向可以改变箭头函数的this。

描述this问题,这里我们可以扩展说明如何去改变this指向,通过bind,call,apply,然后说说他们的区别,懂得多的话,
可以说说他们的实现原理,或者手写bind,call,apply的实现。
复制代码
  • 请介绍一下节流函数和防抖函数,简单实现节流函数和防抖函数
“节流”与“防抖”的本质: 这两个东西都以闭包的形式存在。

它们通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率。

防抖函数:有这样一个按钮,他提供查看你未来老婆的样子,当你在一定时间内多次点击查询时,他只会在你最后一次点击以后,
采取执行查询操作。

节流函数:当你在玩LOL的时候,你在放出大招后的一段时间内,再次点击放大招是不启作用的,因为有一个冷却时间。

代码我就不写在这里了,简易版本的很简单,完整版封装一般我们都使用lodash封装好的。
复制代码
  • 请介绍一下Eventloop(事件循环)
搞懂 Event Loop,是理解 Vue 对 DOM 操作优化的第一步。

Micro-Task 与 Macro-Task
事件循环中的异步队列有两种:macro(宏任务)队列和 micro(微任务)队列。

常见的 macro-task 比如: 
    setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等。
常见的 micro-task 比如: 
    process.nextTick、Promise、MutationObserver 等。
    
大家也知道了当我们执行 JS 代码的时候其实就是往执行栈中放入函数,当遇到异步的代码时,会被挂起并在需要执行的时候,
加入到 Task(有多种 Task) 队列中。
一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,
所以本质上来说 JS 中的异步还是同步行为。

所以 Event Loop 执行顺序如下所示:

首先执行同步代码,这属于宏任务
当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
执行所有微任务
当执行完所有微任务后,如有必要会渲染页面
然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数

微任务包括 process.nextTick ,promise ,MutationObserver,其中 process.nextTick 为 Node 独有。

宏任务包括 script , setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering。

这里很多人会有个误区,认为微任务快于宏任务,其实是错误的。
因为宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话才会先执行微任务。
复制代码
  • 请用一个例子来形象的描述原型链

哈,这个问题我在沸点有发过一个形象的比喻,给面试官逗笑了。

每个门派都有一个祖师爷。

学徒在山上学艺,学成下山后谨记师门教导,施展一身武艺。

恰逢一日对敌,面对敌人的怪异武功,师门好像未曾教过破解之法,便高喊一声祖师爷救我,

刹那间一道白光降于头顶,祖师爷灵魂附体,一套精绝凌厉的拳法杀得敌人措手不及。

但敌人也极是难缠,恐怕非要那门传说中从天而降的掌法才能制敌。

你心中暗自着急,催促着祖师爷赶快发招,这时只听身内传来了祖师的声音:

“MD这破掌法当年偷懒没学,我去把我师祖也叫来问问...”

每个门派(FunctionX)都有一个祖师爷(prototype)。

学徒(object)在山上学艺(= new FunctionX),学成下山后谨记师门教导,

施展一身武艺(http://object.xxxobject.xxx)。

恰逢一日对敌,面对敌人的怪异武功,师门好像未曾教过破解之法(object对象没有yyy方法),

便高喊一声祖师爷救我,刹那间一道白光降于头顶,祖师爷(__proto__)灵魂附体,

一套精绝凌厉的拳法杀得敌人措手不及(继续寻找原型中是否有yyy方法)。

但敌人也极是难缠,恐怕非要那门传说中从天而降的掌法才能制敌。你心中暗自着急,

催促着祖师爷赶快发招,这时只听身内传来了祖师的声音:

“MD这破掌法当年偷懒没学,我去把我师祖也叫来问问...”(如果原型中没有yyy方法,则继续查找原型的原型,是谓原型链)
复制代码
  • 请介绍一下回流(Reflow)与重绘(Repaint)
回流:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,
浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),
然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。

重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,
浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。

由此我们可以看出,重绘不一定导致回流,回流一定会导致重绘。
硬要比较的话,回流比重绘做的事情更多,带来的开销也更大。但这两个说到底都是吃性能的,
所以都不是什么善茬。我们在开发中,要从代码层面出发,尽可能把回流和重绘的次数最小化。
复制代码
  • 请描述一下什么是执行栈
可以把执行栈认为是一个存储函数调用的栈结构,它遵从先进后出的原则。
当开始执行 JS 代码时,首先会执行一个 main 函数,然后执行我们的代码。根据先进后出的原则,后执行的函数会先弹出栈。
复制代码

尾声

至此2020年我所面试的公司大部分面试题都包含了以上内容,至于一些代码图解之类的问题我就没有写上去,太简单了,相信大家都会。后续一些细枝末节的地方我会补充。

最后希望我所总结的面试内容能够对你在2020年的面试中有所帮助。

❤️ 看完帮个忙

如果你觉得这篇内容对你挺有启发,我想邀请你帮我个小忙:

  1. 点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)

  2. 关注公众号「番茄学前端」,我会定时更新和发布前端相关信息和项目案例经验供你参考。

  3. 加个好友, 虽然帮不上你大忙,但是一些业务问题大家可以探讨交流。