Vue:Object变化侦测
1. 什么是变化侦测
Vue.js会自动检测状态并生成DOM,然后将其输出到页面上,这个过程称为渲染,这个渲染过程是声明式的,我们通过模板来描述状态和DOM之间的映射关系。
而通常情况下,我们的页面是不断在更新状态的,此时页面根据状态来重新渲染,想要检测这个过程,就涉及到了变化侦测。
变化侦测有两种类型:“推”和“拉”。国内三大主流框架中的Angular和React都采用“拉”,Vue采用的是“推”。
“推”的优势是,当状态发生变化,Vue能够立刻知道,并将信息推送到各个相关依赖。因此,当知道信息越多,就可以进行更细粒度的更新。
粒度越细,在依赖上追踪所消耗的内存开销就会越大。Vue引入了虚拟DOM,将粒度调整为中等粒度,则一个状态所绑定的依赖不再是具体的DOM节点,而是组件,组件再通知给DOM,大大降低了依赖数量,降低内存损耗。
2. 追踪变化和收集依赖的实现
2.1 JS中的对象追踪变化
在JS中,检测对象变化的方法主要有两种:Object.defineProperty
和Proxy
。
下面我们来对Object.defineProperty
来进行封装,使之成为响应式的:
function defineReactive(data,key,val){
Object.defineProperty(data,key,{
enumerable: true,
configurable: true,
get: function(){
return val;
},
set: function(newVal){
if(val === newVal){
return ;
}
val = newVal;
}
})
}
2.2 收集依赖
收集依赖,就是把模板中用到目标数据的地方先保存起来,等数据发生变化时,把之前收集的依赖循环触发一遍渲染即可。
用一句话总结,就是getter收集依赖,setter触发依赖。
让我们将收集依赖的代码封装成类,并改进一下上面的封装内容,使之能够收集触发依赖。
class Dep{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub);
}
removeSub(sub){
let index = this.subs.indexOf(sub);
if(index > -1