[Vue面试题] 2.0

112 阅读5分钟

isNaN()和Number.isNaN()

对于Number, isNaN()判断是否为NaN; 对于其他类型, isNaN()判断能否转换为Number类型 Number.isNaN()判断是否为NaN, 不存在类型转换的问题

const name = "Lydia Hallie"; 
const age = 21;
isNaN(name)  // true
Number.isNaN(name)  // false

代码, 判断是否启动定时器

let config = { 
    alert: setInterval(() => { 
        console.log('Alert!') 
    }, 1000) 
} 
config = null

setInterval 的回调仍然会被每秒钟调用; 正常来说, JS创建的Object类型储存在栈空间, 变量指针指向null时会触发垃圾回收(garbage collected), 有两个例外: interval对象和timeout对象; 这两种定时器对象只会随着窗口对象的销毁才从栈空间回收。无法通过更改变量的指针指向null的方式通知垃圾回收机自动回收。  如果打算在窗口对象关闭之前销毁窗口对象的栈内存中的interval对象只能通过interval的销毁函数销毁它,interval的销毁函数为clearInterval,timeout的销毁函数为clearTimeout。

回流与重绘

image.png

HTML中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘:

  • 回流(Layout):布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
  • 重绘(Painting):当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制

即改变页面上几何布局的时候触发回流

image.png

Composition API组合式与 Options Api选项式

  • 在逻辑组织和逻辑复用方面,Composition API是优于Options API
  • 因为Composition API几乎是函数,会有更好的类型推断。
  • Composition API tree-shaking 友好,代码也更容易压缩
  • Composition API中见不到this的使用,减少了this指向不明的情况
  • 如果是小型组件,可以继续使用Options API,也是十分友好的

虚拟DOM

一段代码直观表现什么是虚拟DOM和真实DOM

真实DOM
<ul id="list">
    <li class="item">哈哈</li>
    <li class="item">呵呵</li>
    <li class="item">林三心哈哈哈哈哈</li> // 修改
</ul>
let newVDOM = { // 新虚拟DOM
        tagName: 'ul', // 标签名
        props: { // 标签属性
            id: 'list'
        },
        children: [ // 标签子节点
            {
                tagName: 'li', props: { class: 'item' }, children: ['哈哈']
            },
            {
                tagName: 'li', props: { class: 'item' }, children: ['呵呵']
            },
            {
                tagName: 'li', props: { class: 'item' }, children: ['林三心哈哈哈哈哈']
            },
        ]
    }

image.png

虚拟DOM算法操作真实DOM,性能高于直接操作真实DOM虚拟DOM虚拟DOM算法是两种概念。虚拟DOM算法 = 虚拟DOM + Diff算法

Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实DOM,进而提高效率

使用虚拟DOM算法的损耗计算: 总损耗 = 虚拟DOM增删改+(与Diff算法效率有关)真实DOM差异增删改+(较少的节点)排版与重绘

直接操作真实DOM的损耗计算: 总损耗 = 真实DOM完全增删改+(可能较多的节点)排版与重绘

image.png Diff算法是:深度优先算法。 时间复杂度:O(n)

image.png

这个方法作用就是,对比当前同层的虚拟节点是否为同一种类型sameVnode的标签:

  • 是:继续执行patchVnode()方法进行深层比对
  • 否:没必要比对了,直接整个节点替换成新虚拟节点

sameVnode()

function sameVnode(oldVnode, newVnode) {
  return (
    oldVnode.key === newVnode.key && // key值是否一样
    oldVnode.tagName === newVnode.tagName && // 标签名是否一样
    oldVnode.isComment === newVnode.isComment && // 是否都为注释节点
    isDef(oldVnode.data) === isDef(newVnode.data) && // 是否都定义了data
    sameInputType(oldVnode, newVnode) // 当标签为input时,type必须是否相同
  )
}

patchVnode()

这个函数做了以下事情:

  • 找到对应的真实DOM,称为el
  • 判断newVnodeoldVnode是否指向同一个对象,如果是,那么直接return
  • 如果他们都有文本节点并且不相等,那么将el的文本节点设置为newVnode的文本节点。
  • 如果oldVnode有子节点而newVnode没有,则删除el的子节点
  • 如果oldVnode没有子节点而newVnode有,则将newVnode的子节点真实化之后添加到el
  • 如果两者都有子节点,则执行updateChildren函数比较子节点,这一步很重要

updateChildren()

image.png

  • 1、oldS 和 newS 使用sameVnode方法进行比较,sameVnode(oldS, newS)
  • 2、oldS 和 newE 使用sameVnode方法进行比较,sameVnode(oldS, newE)
  • 3、oldE 和 newS 使用sameVnode方法进行比较,sameVnode(oldE, newS)
  • 4、oldE 和 newE 使用sameVnode方法进行比较,sameVnode(oldE, newE)
  • newVNodes有可复用节点时, oldVNode节点移动到新的位置, 新旧nodes指针移动

匹配不到的话, 把旧节点key做一个key -> index表, 然后用newVnode的key去找旧节点复用的位置

所以不建议用index作为for循环的key, 建议使用独一无二的id代替

例如在如下代码, dom列表头部新增, diff算法会让原本可以复用的VNode无法复用:

<ul>                      <ul>
    <li key="0">a</li>        <li key="0">林三心</li>
    <li key="1">b</li>        <li key="1">a</li>
    <li key="2">c</li>        <li key="2">b</li>
                              <li key="3">c</li>
</ul>                     </ul>

sameNode算法命中, 新旧节点存在相同key并比较

patchVnode比较文本发现不相同 -> 更新文本

c节点key=4, 被新增

转载:https://juejin.cn/post/6994959998283907102

Vue3性能提升主要是通过哪几方面体现的 

高内聚,低耦合

  • diff算法优化(会变化的地方加flag标记)
  • 静态提升(不参与更新的元素静态提升, 只会被创建一次, 渲染时直接复用, flag=-1不会被diff)
  • 事件监听缓存(页面在不断的更新的时候,你的事件侦听器并不会重复地销毁再创建)
  • SSR优化

v-if 和 v-for 的优先级哪个高

在 vue2 中 v-for 的优先级更高,但是在 vue3 中优先级改变了。v-if 的优先级更高。