vue响应式实现
Vue 响应式实现原理
Vue 的响应式系统是其核心特性之一,通过数据劫持和依赖收集实现。以下是 Vue 2.x 和 Vue 3.x 响应式实现的主要机制:
Vue 2.x 的响应式实现
Vue 2.x 使用 Object.defineProperty 实现数据劫持,通过递归遍历对象的属性,将其转换为 getter/setter。
数据劫持
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`读取 ${key}`);
return val;
},
set(newVal) {
if (newVal !== val) {
console.log(`设置 ${key} 为 ${newVal}`);
val = newVal;
}
}
});
}
依赖收集与派发更新
- 每个组件实例对应一个
Watcher实例,负责订阅数据变化。 - 在 getter 中收集依赖(
Dep.target指向当前Watcher)。 - 在 setter 中触发依赖更新(调用
Watcher的update方法)。
局限性
- 无法检测对象属性的添加或删除(需使用
Vue.set/Vue.delete)。 - 数组的变异方法(如
push、pop)需通过重写实现响应式。
Vue 3.x 的响应式实现
Vue 3.x 使用 Proxy 替代 Object.defineProperty,解决了 Vue 2.x 的局限性。

Proxy 实现
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
console.log(`读取 ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`设置 ${key} 为 ${value}`);
return Reflect.set(target, key, value, receiver);
}
});
}
依赖收集优化
- 引入
effect函数(类似 Vue 2.x 的Watcher),通过track和trigger实现依赖管理。 - 使用
WeakMap和Map存储依赖关系,提升性能。
优势
- 支持动态添加/删除属性。
- 默认支持数组索引和长度变化。
- 性能更高,无需递归遍历对象。
响应式系统的核心流程
-
初始化阶段

- 遍历数据对象,劫持属性的访问和修改。
- Vue 2.x 递归转换,Vue 3.x 惰性转换(按需代理)。
-
依赖收集
- 在属性被访问时(getter),将当前依赖(如
Watcher或effect)记录到Dep中。
- 在属性被访问时(getter),将当前依赖(如
-
派发更新
- 在属性被修改时(setter),通知所有依赖触发更新(如重新渲染组件)。
示例对比
Vue 2.x 示例
const vm = new Vue({
data: { count: 0 }
});
vm.count++; // 触发 setter,更新视图
Vue 3.x 示例
const state = reactive({ count: 0 });
effect(() => {
console.log(state.count); // 自动追踪依赖
});
state.count++; // 触发 effect 重新执行
注意事项
- Vue 2.x 中,响应式数据需在
data中预先声明。 - Vue 3.x 的
ref和reactive需根据场景选择:ref用于基本类型,通过.value访问。reactive用于对象,直接解构会丢失响应性(需使用toRefs)。






