关于Vue框架部分,总会涉及一些高频面试题,大多数看似非常初级。 有些纯记忆性质的面试题,我们在官方文档很容易就能查看到。 举个例子: vue组件之间如何通信? vue生命周期有哪些? 这类面试题在文档中就能找到答案,网络上面找到的答案也是千篇一律。大家只要使用过vue并且稍加记忆即可流畅作答。 但是,如果我们也这样回答,那就算自己真的比其他竞争者更有实力,也很难脱颖而出,更别提获得高薪offer了。 怎么才能避免这种情况呢? 很简单,其实面试官提出这类“常见问题”时,就意味着他想要听到“不常见的答案”。 我们只要将回答问题的方式、思路提升一个层级,给出标新立异的高水准解答,拿下高薪Offer就如探囊取物一般简单! 下面young村长就带大家实际操作起来,手把手教你剖析VUE面试题,如何做到“深入浅出”。 (以下内容提取自开课吧全栈课程训练营) v-if和v-for谁的优先级最高? 当面试官提出这个问题时,显然想要考察应聘者对v-if和v-for的“基本功”,同时还想要考察应聘者如何将理论应用到操作里。 基于以上两点,我们可以拓展问题: 当v-if和v-for同时出现时,我们应该怎样优化从而获得更好的性能? 得知了面试官的隐含问题,接下来我们对症下药就可以了。 首先,在源码中找答案: compiler/codegen/index.js(☜文件中的位置) 做个测试如下: 两者同级时,渲染函数如下: _l包含了isFolder的条件判断☝☝ 两者不同级时,渲染函数如下: 先判断条件再决定是否执行☝☝ 正确解答: 1、显然v-for优先于v-if被解析(把你是怎么知道的告诉面试官) 2、如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能 3、要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环 4、如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项 VUE组件data为什么必须是函数 我们都知道,VUE的data实例必须是函数,那么有没有与之相反的情况呢?答案是肯定的,因为VUE的根实例就没有“必须是函数”这个限制的。 所以,我们在对这道题进行解答之前,我们还要考虑与“VUE组件data对象实例”所对应的“VUE的根实例”。 通过两者的对比论证,会让我们的答案更加清晰缜密、更有说服力。 源码中找答案: src\core\instance\state.js - initData() 文件中的位置☝ 通过源码得知: 函数每次执行都会返回全新data对象实例 测试代码如下: 然而程序甚至无法通过vue检测☟☟ 正确解答: Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,那么状态变更将会影响所有组件实例,这是不合理的; 采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。 而在Vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。 vue中key的作用和工作原理 为了表达的更加透彻,我们可以通过对比测试来寻找key的工作原理: 首先是在源码中找答案,它在文件中的位置是☟ src\core\vdom\patch.js - updateChildren() 测试代码如下: ![]() 本次案例代码重现的是以下过程☟☟: ![]() 在不使用Key的情况下是这样的☟☟: ![]() 如果使用Key☟☟: // 首次循环patch A A B C D E A B F C D E // 第2次循环patch B B C D E B F C D E // 第3次循环patch E C D E F C D E // 第4次循环patch D C D F C D // 第5次循环patch C C F C // oldCh全部处理结束,newCh中剩下的F,创建F并插入到C前面 正确解答: 1、key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。 2、另外,若不设置key还可能在列表更新时引发一些隐蔽的bug 3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。 ![]() 你怎么理解vue中的diff算法? 在分析diff算法之前,我们可以看一下VUE的diff算法模型图: ![]() 接下来还是先从源码入手解决问题: 源码分析1:必要性 lifecycle.js - mountComponent() 组件中可能存在很多个data中的key使用 源码分析2:执行方式 patch.js - patchVnode() patchVnode是diff发生的地方 整体策略:深度优先,同层比较 源码分析3:高效性 patch.js - updateChildren() 测试代码如下: ![]() 正确解答: 1、diff算法是虚拟DOM技术的必然产物:通过新旧虚拟DOM作对比(即diff),将变化的地方更新在真实DOM上; 另外,也需要diff高效的执行对比过程,从而降低时间复杂度为O(n)。 2、vue 2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,只有引入diff才能精确找到发生变化的地方。 3、vue中diff执行的时刻是组件实例执行其更新函数时,它会比对上一次渲染结果oldVnode和新的渲染结果newVnode,此过程称为patch。 4、diff过程整体遵循深度优先、同层比较的策略;两个节点之间比较会根据它们是否拥有子节点或者文本节点做不同操作; 比较两组子节点是算法的重点,首先假设头尾节点可能相同做4次比对尝试; 如果没有找到相同节点才按照通用方式遍历查找,查找结束再按情况处理剩下的节点; 借助key通常可以非常精确找到相同节点,因此整个patch过程非常高效。 |
|