vue怎么实现数据检测
Vue 数据检测的实现方式
Vue 通过数据劫持和发布-订阅模式实现数据检测,核心机制是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。以下是具体实现方法:
Vue 2.x 基于 Object.defineProperty
通过 Object.defineProperty 劫持对象的属性,在属性被访问或修改时触发 getter/setter:

function observe(data) {
if (!data || typeof data !== 'object') return;
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key]);
});
}
function defineReactive(obj, key, val) {
observe(val); // 递归处理嵌套对象
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
console.log(`获取属性 ${key}: ${val}`);
return val;
},
set(newVal) {
if (newVal === val) return;
console.log(`设置属性 ${key}: ${newVal}`);
val = newVal;
observe(newVal); // 对新值进行劫持
}
});
}
// 使用示例
const data = { name: 'Vue' };
observe(data);
data.name; // 触发 getter
data.name = 'React'; // 触发 setter
Vue 3.x 基于 Proxy
使用 Proxy 代理整个对象,无需递归遍历属性:

function reactive(data) {
if (typeof data !== 'object' || data === null) return data;
const observed = new Proxy(data, {
get(target, key, receiver) {
console.log(`获取属性 ${key}`);
const result = Reflect.get(target, key, receiver);
return reactive(result); // 懒递归
},
set(target, key, value, receiver) {
console.log(`设置属性 ${key}: ${value}`);
return Reflect.set(target, key, value, receiver);
}
});
return observed;
}
// 使用示例
const data = reactive({ user: { name: 'Alice' } });
data.user.name; // 触发 getter
data.user.name = 'Bob'; // 触发 setter
数组的特殊处理
Vue 2.x 中需对数组方法(如 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;
};
});
function observeArray(arr) {
arr.__proto__ = arrayMethods;
}
依赖收集与派发更新
Vue 通过 Watcher 和 Dep 实现依赖管理:
class Dep {
constructor() {
this.subs = new Set();
}
addSub(sub) {
this.subs.add(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
update() {
console.log('数据变更,触发更新');
}
}
实际应用中的优化
- 性能优化:Vue 3.x 的 Proxy 避免了全量递归,按需触发响应。
- 批量更新:通过异步队列(nextTick)合并多次数据变更。
- 虚拟 DOM:数据变化后通过 diff 算法最小化 DOM 操作。






