vue数据响应式实现
Vue 数据响应式实现原理
Vue 的数据响应式是通过 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)实现的,核心是依赖收集和派发更新。
Vue 2.x 的实现
数据劫持
通过 Object.defineProperty 对对象的属性进行劫持,在 getter 中收集依赖,在 setter 中触发更新。
function defineReactive(obj, key, val) {
const dep = new Dep(); // 依赖管理器
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.depend(); // 收集依赖
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify(); // 触发更新
}
});
}
依赖收集
每个响应式属性都有一个 Dep 实例,用于管理依赖(即 Watcher 实例)。当数据被访问时,当前 Watcher 会被添加到 Dep 中。

class Dep {
constructor() {
this.subs = [];
}
depend() {
if (Dep.target) {
this.subs.push(Dep.target);
}
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
Watcher
Watcher 是观察者,负责执行更新操作(如渲染视图)。在初始化时,会将当前 Watcher 设置为 Dep.target,触发 getter 收集依赖。
class Watcher {
constructor(vm, key, cb) {
this.vm = vm;
this.key = key;
this.cb = cb;
Dep.target = this;
this.value = vm[key]; // 触发 getter,收集依赖
Dep.target = null;
}
update() {
this.value = this.vm[this.key];
this.cb(this.value);
}
}
Vue 3.x 的实现
Vue 3.x 使用 Proxy 替代 Object.defineProperty,解决了 Vue 2.x 中无法检测数组和对象新增属性的问题。

Proxy 数据劫持
通过 Proxy 拦截对象的操作,包括属性访问、赋值、删除等。
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key); // 收集依赖
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发更新
return true;
}
});
}
依赖管理
Vue 3.x 使用 effect 替代 Watcher,通过 track 和 trigger 管理依赖。
const targetMap = new WeakMap();
function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => effect());
}
}
let activeEffect;
function effect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
总结
- Vue 2.x:通过
Object.defineProperty劫持数据,结合Dep和Watcher实现依赖收集和派发更新。 - Vue 3.x:通过
Proxy实现更全面的数据劫持,使用effect、track和trigger管理依赖,性能更好且支持更多操作。






