问题来源:https://segmentfault.com/q/1010000015780995
问题描述:Vue通过Object.defineProperty检测数据的变化,所以无法监控数组的添加操作也是可以理解的,因为这个检测绑定操作已经对构造函数中的所有属性进行了。
但官方原文:由于JavaScript的限制,Vue无法检测到以下变化的数组:
当你使用索引直接设置一个项目时,例如:vm.items[indexOfItem]=newValue当你修改数组的长度时,例如,这句话是什么意思:vm.items.length=newLength?我测试过Object.defineProperty可以通过index属性设置属性的访问器属性,那么为什么不能监控呢?
论坛上有人说,因为数组长度是可变的,即使长度是5,也可能没有索引4。我只想问这个答案从何而来。如果长度被修改,新添加的元素将被添加到末尾,其值是未定义的。它们的值可以通过索引获得。为什么叫“可能没有指数4”?
既然我们知道了为什么数组的长度不能遍历所有的元素并通过索引这个属性来添加所有的set和get,我们可以同时更新视图吗?
如果非要说的话,考虑到性能问题,假设元素内容只有4个有意义的值,但是长度真的是1000,所以不能对1000个元素做检测操作。但是官方说由于JS限制,我想知道这个限制是什么。非常感谢你帮我解决这个问题。
面对这个问题,我想说,首先,长度为1000但只有4个元素的数组不一定会影响性能,因为js中数据的遍历包括forEach、map、filter、some等。除了for循环(for,for.的),其他遍历是键值的遍历。也就是说,除了这四个元素之外的空缺不会被遍历(执行回调),所以不会有性能损失,因为如果循环体中没有操作,性能影响可以忽略不计。以下是长度为10000但只有两个元素的数组分别被for和forEach遍历的结果:
var arr=[1];arr[10000]=1 function a(){ console . time()for(var I=0;长度;I)console . log(1)console . timeend()} a();//default : 567.1669921875 MSA();//default : 566 . 2451171875 msfunction b(){ console . time()} arr . foreach(item={ console . log(2)})console . timeend()} b();//default : 0.81982421875 msb();//default:43481453125ms,我们可以看到结果非常明显,但是如果for循环中没有操作,两个速度差不多。
其次,我想说我不知道这个极限是多少() ()
Object.defineProperty()方法直接定义对象的新属性,或者修改对象的现有属性并返回该对象。数组的索引也是一个属性,所以我们可以监听数组元素的变化
var arr=[1,2,3,4]arr.forEach((item,index)={ object . definepreproperty(arr,index,{ set : function(val){ console . log(' set ')item=val },get : function(val){ console . log(' get ')return item } })})arr[1];//get 2ar[1]=1;//set 1但是,如果我们添加一个新元素,我们将不会触发监控事件,因为我们没有监控这个新属性,删除一个属性也是如此。
回到主题的问题,既然数组可以被监控,为什么vue检测不到vm.items[indexOfItem]=newValue引起的数组元素的变化,即使这个下标对应的元素存在并且被监控?
为了理解这个问题,我用vue的源代码进行了测试。以下是用于数据监控的vue的源代码:
可以看到,当数据为数组时,会停止对数据属性的监控。让我们修改源代码:
当数据是一个数组时,它的属性仍然被监控,然后在defineReactive函数的get和set中打印一些东西,这样我们就可以知道get和set被调用了。这里有一个简单的判断,只看数组元素的get和set
然后写了一个简单的案例,主要测试用vm.items[indexOfItem]=newValue改变数组元素是否可以被监控,并相应地呈现页面
运行页面
如您所见,在运行get六次之后,我们的数组长度是3,这意味着数组已经被遍历了两次。次数不多,页面渲染一次,可能多次触发数据监控事件,即使数据只使用一次,具体需要看特殊代码怎么写。以此为例。当被监控的数据是一个数组时,将运行DEPENDARY函数(代码在上图中的get实现中)。在这个函数中,数组被遍历,所以它会得到三次。这里,vue对arr数组在数据中的监控主要触发了DEPENDARY函数。
例如,当我们单击其中一个元素时,我会单击3
您可以看到该集合将运行一次,然后数据将被更新,页面将被重新呈现,数组将被再次遍历两次。
但是!数组确实会变得有响应,这意味着js语法不会限制对数组的监控。
这里我们用长度为3的数组进行测试。当我把数组的长度增加到9时,
可以看到,在18次get之后,数组被遍历了两次,在渲染的时候点击一个元素也被遍历了两次。
通过上面的实验,我的结论是数组可以在vue中响应性的更新,但是我不明白特殊的原因是什么,我没有加入这个函数。我希望知道的人会毫不犹豫地给出建议
2018年7月27日补充
github上的问题特别大
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。