- Vue 是怎么知道数据改变?(Object.defineProperty)
- Vue 在数据改变时,怎么知道通知哪些视图更新?(依赖收集)
- Vue 在数据改变时,视图怎么知道什么时候更新?(依赖更新)
1、defineProperty
- get 值是一个函数,当属性被访问时,会触发 get 函数
- set 值同样是一个函数,当属性被赋值时,会触发 set 函数
Object.defineProperty的缺点:
- 深度监听,需要递归到底,一次性计算量大,所以vue3.0用proxy
- 无法监听新增属性和删除属性,所以需要用Vue.set,Vue.delete
2、依赖收集
data 中的声明的每个属性,都拥有一个数组,保存着 谁依赖(使用)了 它。
数据知道谁依赖它之后,它就可以在发生改变的时候,通知 依赖它的页面,从而让页面完成更新。
实际上,会依赖 name 的地方,不只是页面,还会有 computed,watch… 等等,但是这里我们全部使用页面一词替代。
什么时候收集
当 页面 A 读取了 name 时,会触发 name 的 get 函数,此时,name 就会保存 页面A 的 watcher 。
3、依赖更新
什么时候更新
当 name 改变的时候,name 会遍历自己的 依赖收集器 subs,逐个通知 watcher,让 watcher 完成更新
这里 name 会通知 页面A,页面A 重新读取新的 name ,然后完成渲染
4、深度监听
对数据的监听只监听对象和数组,所以vue的数据都在一个对象当中。然后observer这个对象。
对于对象的每个值,如果还是引用类型,就继续observer这个值。
function observer(target){
if(typeof target!=='object'||target===null){//只监听对象和数组
return target
}
for( let key in target){
defineRective(target,key,target[key])
}
}
function defineRective(target,key,value){
observer(value)
Object.defineProperty(target,key,{
get(){
return value;
},
set(newValue){
if(newValue!==value){
value=newValue;
update();
}
}
})
}