浅谈Vue为什么不能检测数组变动

2020-06-12 20:50:00易采站长站整理


var arr = [1,2,3,4]arr.forEach((item,index)=>{
Object.defineProperty(arr,index,{
set:function(val){
console.log('set')
item = val
},
get:function(val){
console.log('get')
return item
}
})
})
arr[1]; // get 2
arr[1] = 1; // set 1

但是我们新增一个元素,就不会触发监听事件,因为这个新属性我们并没有监听,删除一个属性也是。

再回到题主的问题,既然数组是可以被监听的,那为什么vue不能检测

vm.items[indexOfItem] = newValue
导致的数组元素改变呢,哪怕这个下标所对应的元素是存在的,且被监听了的?

为了搞清楚这个问题,我用vue的源码测试了下,下面是vue对数据监测的源码:

可以看到,当数据是数组时,会停止对数据属性的监测,我们修改一下源码:

使数据为数组时,依然监测其属性,然后在defineReactive函数中的get,set打印一些东西,方便我们知道调用了get以及set。这里加了个简单判断,只看数组元素的get,set

然后写了一个简单案例,主要测试使用

vm.items[indexOfItem] = newValue
改变数组元素能不能被监测到,并响应式的渲染页面

运行页面

可以看到,运行了6次get,我们数组长度为3,也就是说数组被遍历了两遍。两遍不多,页面渲染一次,可能多次触发一个数据的监听事件,哪怕这个数据只用了一次,具体的需要看尤大代码怎么写的。就拿这个来说,当监听的数据为数组时,会运行dependArray函数(代码在上面图中get的实现里),这个函数里对数组进行了遍历取值操作,所以会多3遍get,这里主要是vue对data中arr数组的监听触发了dependArray函数。

当我们点击其中一个元素的时候,比如我点击的是3