注释:在 Vue 的数据绑定中会对一个对象属性的变化进行监听,并且通过依赖收集做出相应的视图更新
一个对象所有类型的属性变化都能被监听到吗?
之前用 Object.defineProperty通过对象的 getter/setter简单的实现了对象属性变化的监听,并且去通过依赖关系去做相应的依赖处理。
但是,这是存在问题的,尤其是当对象中某个属性的值是数组的时候。
正如 Vue 文档所说:
由于 JavaScript 的限制,Vue 无法检测到以下数组变动:
对于响应式数组,当浏览器支持_proto_属性时,使用push等方法时先从其原型arrayMethods上寻找push方法,也就是重写后的方法,处理之后数组变化会通知到其订阅者,更新页面,当在arrayMethods上查询不到时会向上在Array.prototype上查询;
当浏览器不支持_proto_属性时,使用push等方法时会从数组自身上查询,如果查询不到会向上再Array.proptotype上查询。
对于非响应式数组,当使用push等方法时会直接从Array.prototype上查询。
值得一提的是源码中通过判断浏览器是否支持_proto_来分别使用protoAugment和copyAugment方法将重写后的数组方法应用到数组中,这是因为对于IE10及以下浏览器是不支持_proto_属性的
判断当前环境是否可以使用对象的_proto_属性,该属性在IE11及更高浏览器中使用 export const hasProp = 'proto' in {}
结论:
在将数组处理成响应式数据后,如果使用数组原始方法改变数组时,数组值会发生变化,但是并不会触发数组的setter来通知所有依赖该数组的地方进行更新,为此,vue通过重写数组的某些方法来监听数组变化,重写后的方法中会手动触发通知该数组的所有依赖进行更新。
Vue重新的属性
push pop shift unshift splice sort reverse