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) {
if (newVal !== val) {
console.log(`设置 ${key}`);
val = newVal;
}
}
});
}
在 Vue 3 中,使用 Proxy 代理整个对象,无需递归遍历:

function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
console.log(`读取 ${key}`);
return target[key];
},
set(target, key, newVal) {
if (target[key] !== newVal) {
console.log(`设置 ${key}`);
target[key] = newVal;
}
return true;
}
});
}
依赖收集与派发更新
Vue 通过依赖收集(Dependency Tracking)建立数据与视图的关联:
- Watcher:每个组件实例对应一个 Watcher,负责监听数据变化并触发更新。
- Dep:每个响应式属性关联一个 Dep(依赖管理器),用于存储所有依赖该属性的 Watcher。
当数据被读取时,触发 getter 并将当前 Watcher 添加到 Dep 中:

get() {
if (Dep.target) { // 当前 Watcher
dep.addSub(Dep.target); // 收集依赖
}
return val;
}
当数据被修改时,触发 setter 并通知所有关联的 Watcher 更新:
set(newVal) {
val = newVal;
dep.notify(); // 通知所有 Watcher
}
数组响应式处理
Vue 对数组方法(如 push、pop)进行重写,通过拦截原型方法实现响应式:
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift'].forEach(method => {
const original = arrayProto[method];
arrayMethods[method] = function(...args) {
const result = original.apply(this, args);
dep.notify(); // 触发更新
return result;
};
});
性能优化
- 异步更新队列:Vue 将多次数据变化合并为一次更新,通过
nextTick实现批量 DOM 渲染。 - 虚拟 DOM:通过 Diff 算法最小化 DOM 操作,提升渲染效率。
总结
Vue 响应式系统的核心是通过数据劫持和依赖收集实现自动更新。Vue 2 使用 Object.defineProperty,Vue 3 升级为 Proxy,解决了深层嵌套和数组监听的问题,同时优化了性能。






