这篇文章是作者在求职过程所总结的Vue相关面试题及其答案。如果看不懂的话,可以配合其他博主的文章来看,我这里只是面试题及其答案,不会全方面来讲解,毕竟每一个知识点扯出来都能写一篇文章了。本篇是Vue知识点的最后一篇,下一篇文章还是面试篇,应该会出一篇在前端领域中的必须掌握的网络知识。希望读者还是能阅读一下,我在求职中前端网络基本是每个公司都会问的,特别是大厂,例如腾讯、字节、美团。
为什么v-if和v-for不能作用在同一个元素上
当 Vue 处理指令时,v-for的优先级比v-if高,会直接渲染v-for所有的元素,造成资源的浪费。配合使用v-for和computed性能最优。
v-for为什么要使用key
列表数据修改时,Vue会根据key值去判断某个元素是否修改,如果修改,则重新渲染这一元素,否则复用之前的元素。
这里可以继续深问,index可以作为v-for的key吗?为什么?答案可以参考下个问题。
为什么不使用index来作为v-for的key
当数组在增加删除元素时,index是变化的,会导致index变化的元素重新渲染。因此建议使用不变的值来作为key。
事件修饰符主要有哪些
- stop 阻止事件冒泡
- native 绑定原生事件
- once 事件只执行一次
- prevent 阻止默认事件
- caption 用于事件捕获
- self 将事件绑定在自身身上,相当于阻止事件冒泡
scope实现原理
Vue在编译的时候就会给当前组件的每一个html标签加上一个data-v-hash的属性并且属性的值是一个哈希值,然后在样式中Vue会使用属性选择器去选到对应的哈希值,从而达到但组件样式的局部化。
谈谈你对nextTick的理解
nextTick是指在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,可以获得更新后的DOM。
Vue在更新Dom的时候是异步执行的,只要监听到数据变化,Vue将开启一个队列,并同时缓存同一事件循环中的所有数据变更。如果同一个Watcher被多次触发,只会被推入一次。然后在下一次事件循环中Vue会刷新队列并执行实际工作。nextTick内部对异步队列尝试使用原生的Promise.then、MutationObserver和setImmediate,如果执行环境不支持,则会采用setTimeout(fn, 0)代替 。
谈谈你对diff算法的理解
传统的diff算法是通过递归遍历比较两种树形结构,查找完差异之后去计算出最小转换方式。时间复杂度O(n ^ 3)。
Vue的diff算法的时间复杂度是O(n)。这里看不懂可以先跳过,我面了这么几十场面试就被问过两次。它是内部是这样子实现的,diff算法是写在patch函数中,它用来比较两个虚拟DOM,然后执行相对应的DOM操作。
1.判断新老节点是否相同,如果不相同,老节点直接替换成新节点。
2.如果相同,调用patchVnode函数。
(1)如果新老节点都有子节点,而且它们不一致,将会调用updateChildren函数。
(2)如果老节点没有子节点而新节点有子节点,则需要先清空老节点的文本内容,然后为其新增子节点
(3)如果老节点有子节点而新点没有子节点,则需要在删除该老节点的子节点
(4)如果新老节点都没有子节点,比较文本节点,如果不相等,则将旧节点的文本替换成新节点的文本
3.接下来是这个diff算法的核心updateChildren函数
(1)先创建新、老节点数组的头指针、尾指针,然后当老节点数组的头指针小于等于尾指针并且新节点数组的头指针小于等于尾指针时,开启循环遍历。
(2)循环遍历过程
a.比较新、老节点数组头指针指向的节点,如果相同,让子节点重复第2步,新老节点数组的头指针向右移动,也就是索引加1
b.比较新、老节点数组的尾指针指向的节点,如果相同,让子节点重复第2步,新、老节点数组的尾指针向左移动,也就是索引减1
c.比较老节点数组的头指针指向的节点和新节点数组的尾指针指向的节点,如果相同,让它们的子节点重复第2步,然后移动头指针指向的节点到队尾,老节点的头指针索引+1,新节点的尾指针索引-1
d.比较老节点数组的尾指针所指向的节点和新节点数组的头指针所指向的节点,如果相同,让他们的子节点重复第2步,然后尾指针所指向的节点移动到队首,老节点数组的尾指针索引-1,新节点数组的头指针索引-1。
e.否则,查找在老节点数组中新节点数组的节点位置,如果找不到,则在老节点数组创建一个新节点。如果找到了,便将老节点数组的当前节点移动到队尾。
(3)处理剩下的节点
a.当老节点数组的头指针大于尾指针时,将新数组中剩下的节点添加到老节点数组中。
b.当新节点数组的头指正大于尾指针时,将老节点数组剩余的节点删除。
这一块diff算法的内容建议配合着源码来看比较直观,源码我这里就不贴出来了。在学习diff算法之前应该先去了解一下什么是虚拟DOM。
什么是keep-alive组件
keep-alive用于缓存组件的,它只会执行一次,不会被销毁。被keep-alive包裹着的组件只有activated和deactivated的钩子函数
keep-alive的实现原理
1.获取keep-alive下第一个子组件的实例对象,通过它去获取到这个组件的名字。
2.通过组件名去匹配keep-alive的include和exclude,判断当前组件是否需要缓存,不需要缓存则直接返回当前组件的vnode
3.如果需要缓存,判断这个组件是否在缓存数组里面。如果存在,则将它原来位置上的key移除,同时将这个组件的key放到keys数组的最后面
4.如果不存在,则将组件的key放入数组,然后判断当前keys数组的长度是否超过max所设置的范围。如果超过,那么移除使用时间最长的一个组件的key值,即keys数组第一个值。
5.将这个组件的keepAlive设置为true
keep-alive组件的缓存策略使用的是LRU算法,LRU算法也是keep-alive的实现原理。这里还需要去了解一下keep-alive有什么应用?
后续
Vue相关的面试题例如Vue-Router、Vuex、首屏加载、SSR、Vue3、Vite方面的会另外新出一篇专门的文章。
感谢
感谢大家的关注,想了解更多内容的可以关注新运营的公众号,二维码如下,以后发布文章同时也会同步到公众号中。如果有什么不懂需要博主解答的话可以添加我的微信号:WinfansYang