vue如何实现响应式
Vue 响应式原理
Vue 的响应式系统通过数据劫持和依赖收集实现,核心是使用 Object.defineProperty(Vue 2)或 Proxy(Vue 3)来监听数据变化。
数据劫持
在 Vue 2 中,通过 Object.defineProperty 递归地将对象的属性转换为 getter/setter,当数据被访问或修改时触发相应的钩子函数。
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`访问 ${key}`);
return val;
},
set(newVal) {
console.log(`修改 ${key} 为 ${newVal}`);
val = newVal;
}
});
}
在 Vue 3 中,改用 Proxy 实现数据劫持,可以监听整个对象而无需递归遍历属性。

const reactive = (target) => {
return new Proxy(target, {
get(target, key) {
console.log(`访问 ${key}`);
return target[key];
},
set(target, key, value) {
console.log(`修改 ${key} 为 ${value}`);
target[key] = value;
return true;
}
});
};
依赖收集
Vue 通过依赖收集跟踪数据的依赖关系。每个响应式属性都有一个对应的 Dep 实例,用于存储依赖(Watcher)。当数据被访问时,当前 Watcher 会被添加到 Dep 中;当数据被修改时,Dep 会通知所有 Watcher 更新。
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
实现 Watcher
Watcher 是数据和视图之间的桥梁,负责在数据变化时更新视图。

let target = null;
class Watcher {
constructor(vm, exp, fn) {
this.vm = vm;
this.exp = exp;
this.fn = fn;
target = this;
this.vm[this.exp]; // 触发 getter 收集依赖
target = null;
}
update() {
this.fn.call(this.vm, this.vm[this.exp]);
}
}
响应式数据示例
结合以上概念,可以创建一个简单的响应式系统:
function observe(data) {
Object.keys(data).forEach(key => {
let value = data[key];
const dep = new Dep();
Object.defineProperty(data, key, {
get() {
dep.depend();
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
dep.notify();
}
});
});
}
const vm = { count: 0 };
observe(vm);
new Watcher(vm, 'count', (val) => {
console.log(`count 更新为 ${val}`);
});
vm.count++; // 输出 "count 更新为 1"
数组响应式处理
Vue 对数组方法(如 push、pop)进行了特殊处理,通过重写这些方法实现响应式。
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift'].forEach(method => {
const original = arrayProto[method];
arrayMethods[method] = function(...args) {
const result = original.apply(this, args);
this.__ob__.dep.notify(); // 通知更新
return result;
};
});
Vue 3 的改进
Vue 3 使用 Proxy 替代 Object.defineProperty,解决了以下问题:
- 无需递归遍历对象属性。
- 可以监听新增或删除的属性。
- 对数组的支持更自然,无需重写方法。
const reactive = (target) => {
const handler = {
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;
}
};
return new Proxy(target, handler);
};
总结
Vue 的响应式系统通过数据劫持和依赖收集实现数据的自动更新。Vue 2 使用 Object.defineProperty,Vue 3 改用 Proxy,提高了性能和灵活性。理解这些原理有助于更好地使用 Vue 并解决相关问题。






