vue如何实现数据拦截
Vue 数据拦截的实现方式
Vue 的数据拦截主要通过 响应式系统 实现,核心依赖于 Object.defineProperty(Vue 2)或 Proxy(Vue 3)。以下是具体实现方法:
Vue 2 使用 Object.defineProperty
Vue 2 通过递归遍历对象的属性,将每个属性转换为 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;
}
}
});
}
const data = { name: 'Vue' };
defineReactive(data, 'name', data.name);
data.name = 'React'; // 触发 setter
console.log(data.name); // 触发 getter
- 缺点:无法检测新增/删除的属性(需通过
Vue.set/Vue.delete处理),且对数组的拦截需要特殊处理。
Vue 3 使用 Proxy
Vue 3 改用 Proxy 实现数据拦截,能直接监听对象和数组的所有操作。
// 简化版实现
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
console.log(`读取 ${key}: ${target[key]}`);
return target[key];
},
set(target, key, value) {
console.log(`设置 ${key}: ${value}`);
target[key] = value;
return true;
},
deleteProperty(target, key) {
console.log(`删除 ${key}`);
delete target[key];
return true;
}
});
}
const data = reactive({ name: 'Vue' });
data.name = 'React'; // 触发 set
delete data.name; // 触发 deleteProperty
- 优势:支持动态增删属性,无需额外 API,且性能更高。
数组的特殊处理
Vue 2 通过重写数组的变异方法(如 push、pop)实现拦截:
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop'].forEach(method => {
const original = arrayProto[method];
arrayMethods[method] = function(...args) {
console.log(`数组操作: ${method}`);
return original.apply(this, args);
};
});
const arr = [];
arr.__proto__ = arrayMethods;
arr.push(1); // 触发拦截
响应式系统的依赖收集
Vue 在拦截数据时会结合 依赖收集(Dep 类)和 观察者模式(Watcher),在数据变化时触发视图更新。
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 watchEffect(fn) {
target = fn;
fn();
target = null;
}
const dep = new Dep();
watchEffect(() => {
dep.depend();
console.log('视图更新');
});
dep.notify();
总结
- Vue 2:基于
Object.defineProperty,需处理对象和数组的局限性。 - Vue 3:基于
Proxy,提供更全面的拦截能力,无需特殊处理。 - 核心目标:实现数据变化时自动触发视图更新,结合依赖收集机制优化性能。







