1、Vue3 使用 Proxy 代替 Vue2 中的 Object.defineProperty 来实现响应式系统,这使得对整个对象的代理更加高效和全面。它通过依赖追踪和触发机制,确保只有实际变化的部分重新渲染,从而优化性能
一、Vue2 的响应式:
Object.defineProperty
在 Vue2 中,响应式系统是通过 Object.defineProperty() 实现的:
javascript
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`访问属性: ${key}`);
return val;
},
set(newVal) {
console.log(`修改属性: ${key}`);
val = newVal;
}
});
}
这种方式的特点是:
-
每个属性都要单独"拦截";
-
必须在初始化时遍历对象的每一个属性;
-
新增或删除属性时无法被监听(因为定义时就固定了);
-
对数组的监听非常麻烦,只能通过重写数组方法(如 push、splice 等)来劫持。
👉 举例:
css
data: {
user: { name: 'Alice', age: 20 }
}
Vue2 初始化时会遍历 user 对象的所有属性,对每个都调用 Object.defineProperty。
如果之后执行:
ini
this.user.gender = 'female'
这不会触发响应式,因为 gender 是后来新增的属性。
二、Vue3 的响应式:
Proxy
Vue3 使用了 ES6 的 Proxy ,它能直接代理整个对象,不再需要递归遍历每个属性。
核心思想:
使用 Proxy 拦截对象的各种操作(读、写、删、遍历等),然后结合依赖收集与触发机制,实现响应式更新。
基本实现示例:
javascript
const handler = {
get(target, key, receiver) {
console.log(`读取属性: ${key}`);
// 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log(`修改属性: ${key}`);
const result = Reflect.set(target, key, value, receiver);
// 派发更新
return result;
}
};
const proxyUser = new Proxy({ name: 'Alice', age: 20 }, handler);
proxyUser.name = 'Bob';
三、两者的关键差异
| 对比点 | Vue2(Object.defineProperty) | Vue3(Proxy) |
|---|---|---|
| 响应式实现方式 | 对每个属性单独劫持 | 对整个对象代理 |
| 新增/删除属性监听 | 不支持 | 支持 |
| 数组检测 | 重写数组原型 | 原生支持 |
| 性能 | 初始化慢(要递归遍历) | 初始化快(代理一次即可) |
| 深层对象 | 必须递归每一层 | 按需惰性代理(访问时再代理) |
| 可代理类型 | 只能是对象的属性 | 几乎所有类型(对象、数组、Map、Set 等) |
四、依赖追踪与触发机制(核心机制)
无论是 Vue2 还是 Vue3,响应式的本质都离不开 "依赖收集" 与 "依赖触发" 。
1. 依赖收集(track)
当模板或计算属性访问某个响应式数据时,系统会记录下当前依赖它的"副作用函数"(effect)。
scss
effect(() => {
console.log(proxyUser.name); // 依赖收集
});
2. 依赖触发(trigger)
当这个响应式数据被修改时,对应的副作用函数会被重新执行,从而触发界面更新。
ini
proxyUser.name = 'Charlie'; // 触发更新
Vue3 使用了独立的依赖收集系统(effect + track + trigger),相比 Vue2 的 Dep 模型更加模块化、高效。
五、性能优化与现代特性
✅ 惰性代理(Lazy Proxy)
Vue3 在 get 时才会递归代理子对象,而不是一次性全部递归。这大大提升了性能。
✅ 精准依赖追踪
只有被访问的属性才会被追踪,修改其他属性不会触发不相关的更新。
✅ 结构灵活
Proxy 能处理 Map、Set、WeakMap、WeakSet 等复杂结构,使 Vue3 能原生支持更多数据类型的响应式。
六、总结一句话
Vue3 的响应式系统通过 Proxy 实现了"对象级别的全域代理",配合惰性依赖追踪与触发机制,让数据更新更智能、更高效、更自然。
图例:
