Vue响应式原理四:响应式-监听属性变化
存在的问题:
- 每次属性修改后需要手动调用dep.notify()
- 容易遗漏导致依赖不更新
- 多个属性变更时需要多次调用
解决方案:需要实现属性变化的自动监听机制
一 . 响应式监听属性变化
-
- 方案一:Object.defineProperty -> Vue2
-
1.1. 实现原理:通过Object.defineProperty()劫持对象属性的set操作
-
1.2. 关键步骤:
- 1.2.1. 使用Object.keys()遍历对象所有key
- 1.2.2. 对每个key执行defineProperty
- 1.2.3. 在setter中保存新值并通知依赖
-
1.3. 注意事项:不能直接在
setter
中设置obj[key]=newValue
,会导致无限递归
-
1.4. 示例代码如下:
-
Object.keys(obj).forEach(key => {// 这个是一个闭包let value = obj[key];Object.defineProperty(obj, key, {set: function(newValue) {// 不可以这么做,会形成递归(如果把newValue设置给key,相当于又给这个key设置值了,又会调用set, 然后又设置值,又调用set会形成递归调用)// obj[key] = newValue; value = newValue;// 属性发生变化时自动执行对应的响应式函数dep.notify()},get: function() {return value;}})})
-
1.5. 自动通知机制:
- 属性修改触发setter
-
// 修改obj的属性console.log('name发生变化时----------------------------------------');obj.name = 'kobe'```
-
- setter调用dep.notify()
-
// 关键代码:set: function(newValue) {// 不可以这么做,会形成递归(如果把newValue设置给key,相当于又给这个key设置值了,又会调用set, 然后又设置值,又调用set)// obj[key] = newValue; value = newValue;// 属性发生变化时自动执行对应的响应式函数dep.notify()} ```
-
- 属性修改触发setter
-
1.6. 执行效果:修改obj.name或obj.age时,所有依赖函数自动执行并输出最新值,
-
-
1.7. 代码结构:
- 外层定义
Depend类
管理依赖 - 中间使用
defineProperty
设置监听属性变化 - 底层通过
watchFn
收集依赖
- 外层定义
-
- 方案二:new Proxy() -> Vue3 (
暂时不写,后面在写
)
- 方案二:new Proxy() -> Vue3 (