
Vue2 响应式系统的核心是通过 Object.defineProperty 来实现数据劫持。不过,在 Vue 3 中,尤雨溪团队选择使用 Proxy 来重写响应式系统。这个重大的技术决策背后有着深刻的缘由。
Object.defineProperty 的局限性
1. 对数组的有限支持
在 Vue 2 中,Object.defineProperty 无法直接监听数组的变化。Vue 2 不得不重写数组的以下方法来实现响应式:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
这意味着某些数组操作无法被自动检测到:
- 通过索引直接修改数组元素:arr[index] = newValue
- 修改数组长度:arr.length = newLength
2. 动态属性限制
使用 Object.defineProperty 时,必须预先知道对象的所有属性才能将其转换为响应式。这导致了以下问题:
- 无法检测对象属性的添加和删除
- 需要使用特殊的 Vue.set() 和 Vue.delete() 方法
- 降低了开发体验和代码直观性
3. 性能开销
Vue 2 中的响应式系统需要:
- 深度遍历对象的所有属性
- 为每个属性创建 getter 和 setter
- 对嵌套对象进行递归处理
这导致了初始化时的性能开销,特别是在处理大型对象时更为明显。
Proxy 的优势
1. 完整的数组支持
Proxy 可以完全监听数组的所有操作,包括:
- 索引访问和修改
- 长度修改
- 所有数组方法
- 不需要特殊处理即可实现完整的响应式
2. 动态属性追踪
Proxy 提供了更强劲的能力:
- 可以监听对象属性的添加和删除
- 无需预先定义所有属性
- 不再需要 Vue.set() 和 Vue.delete()
- 提供了更自然的对象操作体验
3. 更好的性能
Proxy 的优势在于:
- 懒处理:只有在访问属性时才进行代理
- 无需递归遍历对象的所有属性
- 减少了初始化时的性能开销
- 提供更高效的属性访问机制
实际的代码对比
Vue 2 中的实现:
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
// 依赖收集
return val
},
set: function(newVal) {
if (val === newVal) return
val = newVal
// 触发更新
}
})
}
Vue 3 中的实现:
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
// 依赖收集
const result = Reflect.get(target, key, receiver)
return result
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if (oldValue !== value) {
// 触发更新
}
return result
}
})
}
欢迎补充。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END















- 最新
- 最热
只看作者