- Vue2不能监听数组下标变化(数组API重写),对象属性新增(set API)和删除(delete API),只能监听对象的属性,需要深度遍历。
- Vue3代理整个对象,IE8以下不支持,this指向代理对象。
Object. defineProperty
vue2.x 就是通过 Object.defineProperty 实现数据劫持,把 data 中绑定的属性全部转换成 getter()/setter(),然后结合订阅发布者模式实现响应式。getter()可以读取数据,收集依赖,setter()可以改写数据,在数据发生改变时发布消息通知订阅者,触发监听回调,更新视图。
响应式函数
定义一个响应式函数defineReactive
调用 defineReactive
,数据发生变化触发 update
方法,实现数据响应式。
在对象存在多个 key
情况下,需要进行遍历。
如果存在嵌套对象的情况,还需要在 defineReactive
中进行递归。
当给 key
赋值为对象的时候,还需要在 set
属性中进行递归。
定义一个响应式函数defineReactive
- Object.defineProperty 不能监控数组下标的变化,导致通过数组下标添加的元素不能实时响应,并且- 数组
API
方法无法监听到。
- Object. defineProperty 只能监听对象的属性,导致需要对每个对象、每个属性都进行遍历,如果属性值也是对象,则需要进行深度遍历,造成性能问题。
Vue2
中,增加了 set
、delete
API,并且对数组 API 方法重写进行一个重写。
也可以使用 v-if
和 this.$forceUpdate()
进行强制刷新,但不推荐经常使用。
Proxy
在 Vue3.x 中使用了 Proxy 代替了 Object.defineProperty,因为它是对整个对象进行代理,所以可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除,而且还可以监听数组。
Proxy
不兼容 IE,也没有 polyfill
, defineProperty
能支持到 IE 9 。
响应式方法
定义一个响应式方法 reactive
测试一下简单数据的操作,发现都能劫持。
再测试嵌套对象情况,这时候发现就不那么 OK 了。
如果要解决,需要在 get
之上再进行一层代理。
总结
Object. defineProperty
的缺点。
- 不能监控数组下标的变化
- 无法劫持到对象的删除与添加 属性操作。
- 只能监听对象的属性 ,需要深度遍历。
Vue2
中的兼容处理。
- 增加了
set
、delete
API
- 对数组 API 方法重写进行一个重写。
- 也可以使用
v-if
和 this.$forceUpdate()
进行强制刷新,但不推荐经常使用。
由上可知,Object.defineProperty
与 Proxy
的区别如下:
| Object.defineProperty | Proxy |
---|
定义 | 代理对象某个属性 | 代理整个对象 |
对象新增属性 | ❌ | ✅ |
数组新增修改和 length | ❌ | ✅ |
this | 指向目标对象 | 指向代理对象 |
兼容性 | 兼容 IE | 不兼容 IE8 及以下 |
使用上 | 考虑因素多 | 更方便,方法更多(13 种 handler ) |
扩展阅读