Vue3 Proxy响应式与defineProperty对比
对比Vue2使用Object.defineProperty和Vue3使用Proxy实现响应式的差异。Proxy解决了defineProperty哪些无法解决的问题?Vue3响应式在性能上有哪些提升?
回答
屠龙少年
Object.defineProperty的限制(Vue2)
- 无法检测新增属性:
this.obj.newKey = 'value'非响应式- 需使用
Vue.set(obj, 'key', value)
- 需使用
- 无法检测数组索引修改:
arr[0] = newVal不触发更新- Vue2重写数组方法(push/pop/splice等),但直接索引赋值不行
- 无法检测数组长度变化:
arr.length = 0不触发 - 需要递归遍历:初始化时递归所有属性,对象越大初始化越慢
- 新增/删除需要额外API:
Vue.set/Vue.delete
Proxy的优势(Vue3)
- 拦截所有操作:get/set/has/deleteProperty/ownKeys等13种trap
const proxy = new Proxy(target, { get(target, key, receiver) { track(target, key); // 依赖收集 return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); trigger(target, key); // 触发更新 return result; } }); - 动态属性响应式:新增/删除属性自动触发
- 完整数组支持:索引修改、长度变化自动检测
- Map/Set/WeakMap/WeakSet支持
- 懒响应式(惰性代理):访问时才代理嵌套对象,而非递归
性能提升
- 初始化更快:Proxy无需递归遍历所有属性,只在访问时惰性代理
- 内存占用更小:不需要为每个属性存储dep实例
- 运行时更高效:跳过不必要的遍历
缺点对比:
- Proxy无法polyfill(IE11不支持)
- Proxy特殊对象处理更复杂(如内置对象Date、RegExp)
- Proxy在极个别场景性能略低于defineProperty(但可忽略不计)