vue 响应式实现
Vue 响应式实现原理
Vue 的响应式系统通过数据劫持结合发布-订阅模式实现,核心是 Object.defineProperty(Vue 2.x)或 Proxy(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}: ${val}`);
return val;
},
set(newVal) {
if (newVal !== val) {
console.log(`设置 ${key}: ${newVal}`);
val = newVal;
// 触发更新
}
}
});
}
依赖收集与派发更新
每个响应式属性关联一个 Dep(依赖管理器),在 getter 中收集依赖(Watcher),在 setter 中通知更新:

class Dep {
constructor() {
this.subs = new Set();
}
addSub(watcher) {
this.subs.add(watcher);
}
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
// Watcher 示例
class Watcher {
update() {
console.log('视图更新');
}
}
Vue 3.x 的 Proxy 实现
Vue 3.x 改用 Proxy 实现更高效的响应式:
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key); // 依赖收集
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
trigger(target, key); // 触发更新
}
});
}
数组响应式处理
Vue 2.x 通过重写数组的变异方法(如 push、pop)实现响应式:
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop'].forEach(method => {
const original = arrayProto[method];
arrayMethods[method] = function(...args) {
const result = original.apply(this, args);
// 触发更新逻辑
return result;
};
});
响应式系统的局限性
- 对象属性添加/删除:Vue 2.x 需通过
Vue.set/Vue.delete触发响应。 - 数组索引修改:直接通过索引修改元素(如
arr[0] = newVal)不会触发更新。 - Proxy 兼容性:Vue 3.x 的 Proxy 不支持 IE11 及以下浏览器。
性能优化建议
- 避免频繁操作大型响应式对象。
- 使用
Object.freeze()冻结不需要响应式的数据。 - 在 Vue 3.x 中,通过
shallowRef或shallowReactive减少深层响应式开销。
以上实现展示了 Vue 响应式系统的核心逻辑,实际源码中还包含虚拟 DOM 比对、批量异步更新等优化策略。






