vue数据劫持实现
Vue 数据劫持实现原理
Vue 的数据劫持主要通过 Object.defineProperty 或 Proxy 实现,用于监听对象属性的变化并触发更新。以下是核心实现方式:
基于 Object.defineProperty
-
劫持对象属性 通过
Object.defineProperty重写对象的get和set方法,在属性被访问或修改时触发依赖收集和更新通知。function defineReactive(obj, key, val) { Object.defineProperty(obj, key, { enumerable: true, configurable: true, get() { console.log(`读取属性 ${key}`); return val; }, set(newVal) { if (newVal === val) return; console.log(`更新属性 ${key},新值: ${newVal}`); val = newVal; } }); } const data = { name: 'Vue' }; defineReactive(data, 'name', data.name); -
递归劫持嵌套对象 需要递归处理对象中的嵌套属性,确保所有层级的数据均可被监听。

function observe(obj) { if (typeof obj !== 'object' || obj === null) return; Object.keys(obj).forEach(key => { defineReactive(obj, key, obj[key]); observe(obj[key]); // 递归处理嵌套对象 }); } -
数组方法劫持 由于
Object.defineProperty无法直接监听数组变化,需重写数组的变异方法(如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); console.log(`数组方法 ${method} 被调用`); return result; }; });
基于 Proxy(Vue 3)
Vue 3 使用 Proxy 替代 Object.defineProperty,可直接监听对象和数组的变化,无需递归或重写方法。

function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
console.log(`读取属性 ${key}`);
return Reflect.get(target, key);
},
set(target, key, val) {
if (target[key] === val) return true;
console.log(`更新属性 ${key},新值: ${val}`);
return Reflect.set(target, key, val);
}
});
}
const data = reactive({ name: 'Vue 3' });
依赖收集与派发更新
-
依赖收集 在
get方法中,将当前属性的依赖(如 Watcher)存储到全局的依赖收集器(Dep)中。class Dep { constructor() { this.subscribers = new Set(); } depend() { if (activeEffect) this.subscribers.add(activeEffect); } notify() { this.subscribers.forEach(effect => effect()); } } -
派发更新 在
set方法中,通知所有依赖进行更新。function defineReactive(obj, key, val) { const dep = new Dep(); Object.defineProperty(obj, key, { get() { dep.depend(); // 收集依赖 return val; }, set(newVal) { val = newVal; dep.notify(); // 触发更新 } }); }
总结
- Vue 2:通过
Object.defineProperty递归劫持对象属性,重写数组方法实现监听。 - Vue 3:使用
Proxy直接代理对象,简化监听逻辑,性能更优。 - 依赖收集和派发更新机制确保数据变化时视图自动同步。






