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。
回流与重绘
在HTML中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘:
- 回流(Layout):布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
- 重绘(Painting):当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
即改变页面上几何布局的时候触发回流
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: ['林三心哈哈哈哈哈']
},
]
}
虚拟DOM算法操作真实DOM,性能高于直接操作真实DOM,虚拟DOM和虚拟DOM算法是两种概念。虚拟DOM算法 = 虚拟DOM + Diff算法
Diff算法是一种对比算法。对比两者是旧虚拟DOM和新虚拟DOM,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点,实现精准地更新真实DOM,进而提高效率。
使用虚拟DOM算法的损耗计算: 总损耗 = 虚拟DOM增删改+(与Diff算法效率有关)真实DOM差异增删改+(较少的节点)排版与重绘
直接操作真实DOM的损耗计算: 总损耗 = 真实DOM完全增删改+(可能较多的节点)排版与重绘
Diff算法是:
深度优先算法。 时间复杂度:O(n)
这个方法作用就是,对比当前同层的虚拟节点是否为同一种类型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 - 判断
newVnode和oldVnode是否指向同一个对象,如果是,那么直接return - 如果他们都有文本节点并且不相等,那么将
el的文本节点设置为newVnode的文本节点。 - 如果
oldVnode有子节点而newVnode没有,则删除el的子节点 - 如果
oldVnode没有子节点而newVnode有,则将newVnode的子节点真实化之后添加到el - 如果两者都有子节点,则执行
updateChildren函数比较子节点,这一步很重要
updateChildren()
- 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 的优先级更高。