Vue中Array的变化侦测

前言:之前介绍了Vue中Object的变化侦测,Array中的变化侦测和Object中变化侦测还是有一定的不同的,这一篇就来学习一下。


1.Object与Array变化侦测的不同

Array.push()方法实际上并不会调用getter/setter,并且在ES6之前JS并没有元编程的能力,无法拦截原型方法,而每一个数组实例调用push等方法都是调用的原型上的方法,所以为了追踪变化我们必须使用一个拦截器来拦截数组调用这些原型方法的操作,这样我们就可以监测原型方法的调用了。

2.实现拦截器拦截原型方法

(1)写出拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const arrayProto=Array.prototype
export const arrayMethods=Object.create(arrayProto)
;[
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
].forEach(method=>{
//缓存原始方法
const original=arrayProto[method]
//def函数是我写的一个工具函数,为对象(第一个参数)的,key(第二个参数)设置数值等属性
def(arrMethods,method,function mutator(...args){
const result =original.apply(this,args)
//获取当前数组的Observer
const ob=this.__ob__
ob.dep.notify()//向依赖发送消息
return result
})
})

(2)使用拦截器覆盖支持原型指针的数组的原型对象,或者将拦截器方法挂载到不支持原型指针的数组属性上

3.Array是如何收集依赖的

Array收集依赖的方式和Object是一样的,都是在getter中收集依赖,但是是在拦截器中触发依赖

4.Array的依赖保存在哪里

Array的依赖和Object一样是保存在Dep类的对象中,但是和Object的不同在于Object的Dep对象是保存在defineReactive函数中的一个变量,但是Array的Dep对象是保存在Observer实例上的。至于原因就是,我们在写拦截器的时候需要在执行push等方法的时候可以获取到Dep对象,然后向数组的依赖发送通知

5.侦测数组中元素变化

1
2
3
4
5
6
//observe函数是监听函数
observeArray(items){
for( let i=0;i<items.length;i++){
observe(items[i])
}
}

6.监听新元素的变化

(1)获取新增元素
通过switch case判断执行的操作,将操作的元素放入inserted数组中
(2)使用Observer监听新增元素
使用observerArray()方法对inserted数组进行监听,监听这些新增元素的变化

7.关于Array监听的问题

(1)修改数组第一个元素时是不会被Vue监听到的
(2)修改数组长度时也是不会被Vue监听到的


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!