Vue是如何监听数组变化的

3,287 阅读2分钟

注释:在 Vue 的数据绑定中会对一个对象属性的变化进行监听,并且通过依赖收集做出相应的视图更新

一个对象所有类型的属性变化都能被监听到吗?

之前用 Object.defineProperty通过对象的 getter/setter简单的实现了对象属性变化的监听,并且去通过依赖关系去做相应的依赖处理。

但是,这是存在问题的,尤其是当对象中某个属性的值是数组的时候。

正如 Vue 文档所说:

由于 JavaScript 的限制,Vue 无法检测到以下数组变动:

image.png

对于响应式数组,当浏览器支持_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