dep.notify() 是 Vue2 响应式系统中触发依赖更新的核心方法,也是理解 Vue2 视图"自动更新"的关键。结合之前的响应式代码,我们一步步拆解它的含义、作用和工作流程:
一、先搞懂:dep 是什么?
dep 是 Dependency(依赖)的缩写,是 Vue2 为每个响应式属性创建的「依赖管理器」。
- 每个响应式属性(比如
data里的user.name)都对应一个Dep实例; Dep内部维护一个数组(subs),存放所有"依赖这个属性"的Watcher(更新函数);Dep有两个核心方法:depend():收集依赖(把当前Watcher加入subs数组);notify():通知所有依赖(遍历subs,执行每个Watcher的更新逻辑)。
二、dep.notify() 的核心作用
当响应式属性的值被修改 (触发 setter)时,dep.notify() 会被调用,它的唯一目的是:
通知所有依赖该属性的 Watcher 执行更新 (比如组件重新渲染、计算属性重新计算、watch 回调执行)。
三、完整工作流程(结合代码理解)
我们把 defineReactive、Dep、Watcher、dep.notify() 串起来,看一次完整的"属性修改 → 视图更新":
1. 定义 Dep 类(Vue2 源码核心逻辑简化)
javascript
// 依赖管理器:收集Watcher,触发更新
class Dep {
constructor() {
this.subs = []; // 存放所有依赖当前属性的Watcher
}
// 收集依赖:把当前Watcher加入数组
depend() {
if (Dep.target) { // Dep.target 是当前活跃的Watcher(比如组件渲染Watcher)
this.subs.push(Dep.target);
}
}
// 通知所有Watcher更新
notify() {
// 遍历所有依赖的Watcher,执行update方法
this.subs.forEach(watcher => watcher.update());
}
}
// Dep.target:全局变量,标记当前正在执行的Watcher(渲染/计算/监听)
Dep.target = null;
2. 定义 Watcher 类(更新逻辑的载体)
Watcher 是"更新函数的封装",比如组件渲染函数、watch 回调都对应一个 Watcher:
javascript
class Watcher {
constructor(vm, expr, callback) {
this.vm = vm; // Vue实例
this.expr = expr; // 监听的属性(如 'user.name')
this.callback = callback; // 更新回调(比如重新渲染组件)
this.value = this.get(); // 初始化:访问属性,触发依赖收集
}
// 访问属性,触发getter,收集依赖
get() {
Dep.target = this; // 标记当前Watcher为活跃状态
const value = this.vm[this.expr]; // 访问属性,触发getter → dep.depend()
Dep.target = null; // 重置
return value;
}
// 执行更新(由dep.notify()调用)
update() {
const newVal = this.vm[this.expr]; // 获取新值
this.callback(newVal); // 执行回调(比如重新渲染组件)
}
}
3. 结合响应式属性的 get/set
javascript
function defineReactive(obj, key, val) {
const dep = new Dep(); // 每个属性对应一个Dep
observe(val); // 递归处理嵌套对象
Object.defineProperty(obj, key, {
get() {
dep.depend(); // 收集依赖:把当前Watcher加入dep.subs
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
observe(newVal); // 新值是对象则递归监听
dep.notify(); // 🔥 关键:属性修改,通知所有Watcher更新
}
});
}
4. 实际场景演示
javascript
// 模拟Vue实例
const vm = {
data: { user: { name: '张三' } }
};
// 把data变成响应式
observe(vm.data);
// 创建Watcher:监听user.name,回调是打印新值(模拟组件渲染)
new Watcher(vm.data, 'user.name', (newVal) => {
console.log('视图更新:name变为', newVal);
});
// 第一步:访问属性 → 触发getter → 收集依赖
console.log(vm.data.user.name); // 输出"张三",此时Dep.subs已存入这个Watcher
// 第二步:修改属性 → 触发setter → dep.notify()
vm.data.user.name = '李四';
// 🔥 dep.notify()执行 → 遍历subs → 调用Watcher.update() → 打印"视图更新:name变为 李四"
四、dep.notify() 在 Vue 中的实际表现
在真实的 Vue2 项目中,你看不到 dep.notify() 的直接调用,但它是以下场景的"幕后推手":
javascript
new Vue({
data() {
return { msg: 'hello' };
},
template: `<div>{{ msg }}</div>`
});
// 当你修改 msg 时:
this.msg = 'world';
// 触发 msg 的 setter → dep.notify() → 通知组件渲染Watcher → 组件重新渲染 → 页面显示 'world'
五、补充:Vue3 中的对应逻辑
Vue3 抛弃了 Dep 类,用 track(收集依赖)和 trigger(触发更新)替代:
dep.depend()→track(target, key):收集依赖到targetMap(全局依赖映射表);dep.notify()→trigger(target, key):从targetMap中取出所有依赖,执行更新;
核心逻辑和dep.notify()一致,只是实现更模块化、更高效。
总结
dep.notify() 的本质是:响应式属性值变更后,通知所有依赖该属性的更新逻辑(Watcher)执行,最终实现视图/数据的自动更新 。
它是 Vue2 响应式系统的"触发器",也是连接「属性修改」和「视图更新」的核心桥梁。