我们首先回顾一下 Vue2 中 Object.defineProperty
的缺点:
- 深度监听,需要一次性递归到底(关键在于一次性,如果数据层级很深的话,一次性递归到底很耗时)
- 无法监听新增属性、删除属性(所以有 Vue.set、Vue.delete)
- 无法原生监听数组,需要特殊处理
Vue3 响应式:
Vue3 使用 Proxy 实现响应式,可以监听新增属性与删除属性。
1 | // 响应式函数 |
测试一下,已经实现了对象的监听读取属性、修改属性、新增属性、删除属性。
我们再测试一下对数组的监听:
1 | const arr = [1, 2, 3] |
我们可以直接监听数组。但是发现了另外2个问题:① 我们不应该监听原型属性;② 如果是重复的数据应该不处理。
改进以上问题:
因此我们做如下改进:
我们再测试一下:
现在就可以对数组和对象进行基础的监听了。但是我们还有2个问题没有解决:① 如何实现深度监听;② 如何区分是新增属性还是修改属性。
实现深度监听:
测试数据:
1 | const obj = { |
它值输出了 get info 而并没有输出 get city,说明并没有监听到 city 属性,也就是未实现深度监听。因为我们做如下修改:
再测试一下,实现了深度监听:
Vue2 的 Object.defineProperty
也可以实现深度监听,那 Vue3 的 proxy
的优点在哪呢?Vue2 的 Object.defineProperty
实现深度监听时,会一次性递归到底,计算量大!而 Vue3 的 proxy
是在 get 中实现递归,也就是什么时候 get 什么时候往下一层递归。 Vue3 的 proxy
本质就是你获取到哪一层,哪一层才会触发响应式,并非一次性递归到底,性能得到很大提升。我们看测试就能看出这一点:
测试用例:
1 | const obj = { |
如何判断是新增属性还是修改属性:
只需做如下修改:
测试:
总结:
proxy
可以规避 Object.defineProperty
的问题:
- 深度监听的性能更好
- 可以监听新增属性、删除属性
- 可以监听数组变化
但是 proxy
目前无法兼容所有浏览器,也无法 polyfill。
完整代码:
1 | // 响应式函数 |