最新前端面经新鲜出炉,附本人回答(刚刚面完。。)

166 阅读10分钟

vue双向绑定如何实现的

我: vue的双向绑定在vue2和vue3中是有区别的,先介绍一下vue2中双向绑定的实现原理。在vue2中,实例化vue的时候,vue内部会遍历data中定义的数据,通过Object.defineProperty去拦截data中的每一个属性,给它们添加上get和set方法。当其他地方需要使用到data中的某一个数据的时候,就会触发对应的get,get方法内部维护了一个deps,deps会将该watchers收集起来,然后在数据改变的时候,set方法就会去通知deps中所有的watcher进行视图更新。 vue3中双向绑定的原理和vue2中基本是类似的,区别在于vue3使用proxy替代Object.defineProperty,解决了对象新增属性和直接修改数组下标响应式失效问题。(以为面试官会追问,然而并没有。。。)

参考回答: vue.js 是采用数据劫持结合发布者-订阅者模式的方式,首先vue会使用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会,接着为input会添加监听事件,修改值就会为该属性赋值,触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。

视图变化是如何应用到数据的?

我: 以input框为例,在我们给input绑定了v-model以后,vue其实本质是给他绑定了一个:value和@input事件,在编译的过程中,会使用相应的原生事件做替换,实现对数据的更新。(此处感觉没有回答好。。。)

v-model语法糖是怎样的

我: v-model会根据不用元素,做不同的转化,例如如果目标是一个输入框,那么就会被转化为:value和@input,如果目标是下拉框那么对应的就是@change,如果是选择框那么就是@checked。

vue内置指令如何实现

我: 这里一开始回答成了自定义指令了,面试官说不是,就是想问一下类似v-if v-show这些指令是怎么实现的。

因为我们写在代码中的template和实际上的html是有区别的,vue内部会首先将template模板编译成ast语法树,在ast语法树中会根据这些定义的指令对语法树做转换,转换完成以后,在render函数中会根据指令的意义,以及对应的值,来决定最终dom的生成。

虚拟dom是什么,为什么要虚拟dom

我: 虚拟dom的本质其实就是JS对象,是真实dom元素的一种映射关系,正因为如此,所以虚拟dom可以跨平台。虚拟dom的作用是最大限度的保障性能,因为直接操作真实的dom元素,浏览器开销大,时间复杂度高n3。虚拟dom通过内置的diff算法,可以减少dom层级的比较,降低时间复杂度到n。

vue diff算法

我: vue diff算法其实就是新的虚拟节点和老的虚拟节点的比对过程。diff算法只会做同层比较,在diff的过程中,如果老节点存在,而新节点不存在,那么会直接删除老节点及其子节点。如果老节点不存在,而新节点存在,那么会新创建节点。如果新节点和老节点同时存在,那么需要比对新老节点是否相同。主要通过key以及tag和其他的属性来判断是否相同,,如果不是同一节点,那么会删除老节点,创建新节点。这是对单一节点的比较,如果两个节点相同,那么就需要比对他们的子节点。也就会用到patch的核心 updateChildren函数。在这个函数中,会建立4个指针,分别指向新老节点的首尾,按照头头、尾尾、头尾、尾头的顺序进行比对。如果四个比对都没有发现相同节点,那么就需要根据key建立的map映射来查找新节点中是否包含有老节点。

vue 中的key有什么用

我: key一个很大最用就是刚刚讲到的diff算法做节点比对。其次在vue内部默认会使用就地复用原则,在节点内容单一,并且不会出现更改的时候,这种方法是高效的。但是当节点移动或者删除新增时,如果没有key,就会出现异常情况,这也是不推荐使用数组的index做为key的原因,当你数组中删除了一个值后,vue可能会错误的将下一个元素认为是此元素。同时也不推荐是使用Math.random作为key值,因为这样会使key失去意义。

vue3相比vue2有哪些优化策略

我: 在双向绑定中,vue3使用proxy来替代Object.defineProperty,实现了对对象新增或者删除属性的监听,和数组的完全拦截。vue3中双向绑定的过程和vue2中也有一定的区别,利用了weakMap、Map、Set等数据类型来进行依赖存储。另一方面在diff的过程中,vue3和vue2的diff算法有一定的差异,vue2使用头头头尾的对比方法来进行比对,在vue3中使用前置、后置的预处理结合最长递增子序列的思想进行优化。同时vue3会给节点添加一些patchFlag,在diff的过程中会跳过这些静态节点,节省diff的时间。

vue diff和react diff 的区别

我: 刚刚已经说了vue2和vue3的diff算法,而react的diff算法就相对要简单一些,也是新老节点列表的比对,需要记录一个标识,用来表示旧节点在新节点中的位置。从头到尾,在新节点列表中寻找老节点的位置,找到后和上一个位置进行比对,如果当前节点位置大于上一个节点的位置,那么说明该节点不需要移动,如果发现位置不对,那么将旧节点,移动到该节点在新列表中其前一个节点在新列表位置的后面。 此处并没有说特别清楚,因为本身对react不是很熟悉。。。

nextTick实现原理

我: vue中遵循批量异步更新的策略,防止出现同一个变量多次修改多次更新的问题。nextTick的作用主要是用来在本次dom渲染完毕以后来触发一些事件。比如,修改了一个变量的值,想要通过ref立马拿到修改后的值等等。其主要使用原理是利用了JS事件循环机制,内部实现类似于css的优雅降级,首先会检测是否支持Promise,如果支持的话,就是用Promise,如果不支持会检测MutationObserver,支持MutationObserver就使用,使用Promise和MutationObserver的时候,内部维护的isUsingMicroTask变量会被设置为true,表示使用了微任务,如何上面两个都不支持,会检测setImmediate,如果上面三个都不支持,就使用setTimeout。

react熟悉程度

我: 嗯,熟悉基本的开发相关API,编写业务代码应该没问题,但是对其原理,例如fiber、钩子等实现原理不是很了解。

JS为什么要设计成单线程

我: 准确来说,说JS是单线程,应该是JS引擎执行过程是单线程的,因为如果JS是多线程的,两个JS文件同时执行,并且同时操作了同一个dom,那么就无法判断该遵循哪个的执行结果。

JS中有没有办法实现多线程

我: 有的,JS可以通过worker来开发多线程,一般常用的就是web worker,worker可以开启一个新的线程,来实现js的多线程。worker有一定的限制,例如上面提到的问题,worker不能够操作dom,并且只能同源使用,还有worker不能访问本地js文件,只能使用网络文件。

webwork是用来干嘛的,如何使用

我: worker可以用来处理一些比较费时的计算或者用来完成轮询操作。通过new的方式,传递一个url来实例化一个worker,worker和主线程之间通过postMessage来实现通信。

作用域链

我: 作用域链其实就是作用域之间形成的链式关系,JS中对变量的访问存在限制,例如定义了一个函数,那么在函数中使用某个变量的时候,首先会在当前函数作用域中去寻找这个变量,如果没找到,那么就会继续往上层作用域找,一直到全局作用域。如果都没有找到的话,就会报未定义。作用域链规定了,只能向上查找,不能访问子或者同级作用域内的变量。

说一说闭包

我: 闭包用一句通俗的话来讲,就可以认为是函数里面套了个函数,内部函数使用了外层函数的变量。 闭包的缺点就是因为内部函数引用了外部的变量,所有会导致该变量在内存中常驻,无法被回收,如果代码中存在很多这样的地方,那么可能会照成内存泄漏。闭包的作用也就是他的缺点,如果需要一个变量常驻,那么就可以使用闭包。例如防抖、节流、函数柯里化等等。

是否有写过webpack plugin插件

我: 别问,问就是没有

webpack loader的原理

我: loader其实就是一个函数,可以理解为代码转换器,由webpack的loader runner调用接受原始资源数据作为参数,处理后,将处理结果给到下一个loader,最终输出结果给webpack做下一步编译,loader分为前置、普通、内联、后置loader,同等级的loader执行顺序从上到下,从右到左。(嗯,其实也不知道该怎么回答)

babel原理

我: bable是的主要用来做代码转化。其原理是将普通的js代码,通过@bable/parse转化为AST语法树然后在通过@bable/core 来引用插件做转换得到修改后的AST语法树,最后在将转化后的语法树转为普通代码。

node了解多少

我: 能使用node结合koa框架,搭建简单的服务器,结合mysql做一些crud,以及一些简单的文件相关的操作等。

node中开启多进程的方法

我: 只知道是通过引入child_process模块,具体的api不记得了。。。

基础中间件Connect的原理

我: ???? 不知道

koa中context实现原理

我: 嗯。。。这个。。那个,它集合了request和reponse的功能,其他不知道了

项目中的难点解决办法最终结果

我: 袍哥人:各有各的肚皮疼

加班怎么看

我: 我近视,一般戴着眼睛看

跳槽原因

我: