Vue2.x的数据响应式
图解
浅层分析
总体
- 数据劫持 + 依赖收集(发布订阅者模式)
过程
- vue初始化实例时,遍历data中的所有属性并通过
Object.defineProperty重新定义属性。(把属性都转化为getter、setter) - 获取属性时,调用getter。通知
Dep.depend()进行依赖收集,watcher存储收集的结果 - 更新数据时,调用setter。通知
Dep.notify()进行委托派发,遍历通知依赖的所有watcher更新 wacther触发re-render()进行组件重新渲染
深层分析
-
Observer(将 普通对象 转化为 响应式对象)- 执行
object.defineProperty()进行数据劫持 - 将data中的属性转化成带有getter、setter方法的响应式对象
针对对象的类型做了不同的处理 1. 深层嵌套的对象数据 -- 递归遍历 2. 数组 -- 重写数组的7个方法 push/pop/shift/unshift/reverse/sort/splice - 执行
-
Dep(监听响应式对象数据的变化)- 监听对象的getter、setter
- getter -> dep.depend()【依赖收集】
- setter -> dep.notify() 【派发委托】
- 监听对象的getter、setter
-
Watcher(存储Dep的结果)- 将
Dep.depend()/Dep.notify()结果存入watcher中
- 将
-
Scheduler(watcher的调度器)- 对watcher的调度,将其放入队列中 通过事件循环 管理执行
使用JS实现Object.defineProperty
let obj = {}
let value = '你好'
Object.defineProperty(obj, "key",{
get:function() {
console.log('获取数据')
return value
},
set:function(newValue) {
console.log('更新数据');
value = newValue
}
})
console.log(obj.key);
obj.key = '我很好'
console.log(obj.key);
监听式
let obj = {
name: 'elio',
age: 26,
address: {
country: 'china',
province: 'sz'
}
}
function observer(obj) {
if (typeof obj !== 'object' || obj == null) return
for (const key in obj) {
// 给对象每一项都设置响应式
defineProperty(obj, key, obj[key])
}
}
function defineProperty(obj ,key ,value) {
// 嵌套对象的处理,遍历
observer(value)
Object.defineProperty(obj, key,{
get:function() {
console.log(`读取${key}成功`)
return value
},
set:function(newValue) {
if (newValue === value) return
// 3.针对对象的设置
observer(value)
console.log(`监听设置成功,${newValue}`);
value = newValue
}
})
}
// 执行监听
observer(obj)
// obj.age = 18 // 监听设置成功,18
// obj.address.country = 'USA'
/**
读取address成功
监听设置成功,USA
*/
// 3
obj.address = {
email: '123@163.com'
}
obj.address.email = 'asdasd'