vue如何实现数据拦截
Vue 数据拦截的实现方式
Vue 的数据拦截主要依赖于 Object.defineProperty 或 ES6 的 Proxy,用于监听数据变化并触发视图更新。以下是具体实现方法:
使用 Object.defineProperty
Object.defineProperty 是 Vue 2.x 的核心实现方式,通过劫持对象的属性实现数据响应式。

const data = { name: 'Vue' };
let value = data.name;
Object.defineProperty(data, 'name', {
get() {
console.log('获取值');
return value;
},
set(newVal) {
console.log('设置值');
value = newVal;
// 触发视图更新逻辑
}
});
data.name; // 输出 "获取值"
data.name = 'React'; // 输出 "设置值"
使用 Proxy
Vue 3.x 改用 Proxy 实现数据拦截,能够直接监听整个对象而非单个属性。

const data = { name: 'Vue' };
const proxy = new Proxy(data, {
get(target, key) {
console.log('获取值');
return target[key];
},
set(target, key, value) {
console.log('设置值');
target[key] = value;
// 触发视图更新逻辑
return true;
}
});
proxy.name; // 输出 "获取值"
proxy.name = 'React'; // 输出 "设置值"
数组拦截的特殊处理
由于 Object.defineProperty 无法直接拦截数组方法,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) {
console.log('拦截数组方法');
return original.apply(this, args);
};
});
const arr = [];
arr.__proto__ = arrayMethods;
arr.push(1); // 输出 "拦截数组方法"
对比与选择
- Vue 2.x:使用
Object.defineProperty,需递归遍历对象属性,对数组需特殊处理。 - Vue 3.x:使用
Proxy,支持监听动态新增属性,性能更优,但需注意浏览器兼容性。
实际应用示例
在自定义数据拦截时,可以结合发布-订阅模式实现简单的响应式系统:
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
let target = null;
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) {
value = newVal;
dep.notify();
}
});
});
}
const data = { count: 0 };
observe(data);
function watcher(fn) {
target = fn;
fn();
target = null;
}
watcher(() => {
console.log(`Count is: ${data.count}`);
});
data.count = 1; // 输出 "Count is: 1"
通过以上方法,可以实现类似 Vue 的数据拦截与响应式更新机制。






