问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

学习笔记:vue为什么不能监听数组属性的变化

发布网友 发布时间:2022-04-24 02:40

我来回答

3个回答

懂视网 时间:2022-05-14 21:30

这句话是什么意思?我测试了下Object.defineProperty是可以通过索引属性来设置属性的访问器属性的,那为何做不了监听?

有些论坛上的人说因为数组长度是可变的,即使长度为5,但是未必有索引4,我就想问问这个答案哪里来的,修改length,新增的元素会被添加到最后,它的值为undefined,通过索引一样可以获取他们的值,怎么就叫做“未必有索引4”了呢?

既然知道数组的长度为何不能遍历所有元素并通过索引这个属性全部添加set和get不就可以同时更新视图了吗?

如果非要说的话,考虑到性能的问题,假设元素内容只有4个有意义的值,但是长度确实1000,我们不可能为1000个元素做检测操作。但是官方说的由于JS限制,我想知道这个限制是什么内容?各位大大帮我解决下这个问题,感谢万分



面对这个问题,我想说的是,首先,长度为1000,但只有4个元素的数组并不一定会影响性能,因为js中对数据的遍历除了for循环还有forEach、map、filter、some等,除了for循环外(for,for...of),其他的遍历都是对键值的遍历,也就是除了那四个元素外的空位并不会进行遍历,所以也就不会造成性能损耗,因为循环体中没有操作的话,所带来的性能影响可以忽略不计,下面是长度为10000,但只有两个元素的数组分别使用for及forEach遍历的结果:

var arr = [1]; arr[10000] = 1
function a(){
 console.time()
 for(var i = 0;i<arr.length;i++)console.log(1)
 console.timeEnd()
}
a(); //default: 567.1669921875ms
a(); //default: 566.2451171875ms

function b(){
 console.time()
 arr.forEach(item=>{console.log(2)})
 console.timeEnd()
}
b(); //default: 0.81982421875ms
b(); //default: 0.434814453125ms

可以看到结果非常明显,不过,如果for循环中不做操作的话两者速度差不多

其次,我要说的是,我也不知道这个限制是什么 (????) ╮( ??ω?? )╭

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。数组的索引也是属性,所以我们是可以监听到数组元素的变化的

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对数据监测的源码:
1.png

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

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

然后写了一个简单案例,主要测试使用vm.items[indexOfItem] = newValue改变数组元素能不能被监测到,并响应式的渲染页面
3.png

运行页面
5.png

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

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

可以看到会先运行一次set,然后数据更新,重新渲染页面,数组又是被遍历了两遍。

但是!!!数组确实变成响应式的了,也就是说js语法功能并不会限制数组的监测。

这里我们是用长度为3的数组测试的,当我把数组长度增加到9时
7.png

可以看到,运行了18次get,数组还是被遍历了两遍,点击某个元素同理,渲染的时候也是被遍历两次。
8.png

有了上面的实验,我的结论是数组在vue中是可以实现响应式更新的,但是不明白尤大是出于什么考虑,没有加入这一功能,希望有知道的大佬们不吝赐教

相关文章:

vue中数组变化检测问题

为什么 返回的json不能 转为数组

相关视频:

数组变动检测-麦子学院Vue.js视频教程

热心网友 时间:2022-05-14 18:38

不太理解你的疑问在哪里,因为 Vue 不能侦测的是直接对著数组的某个索引赋值,例如 replys[1] = {},但是你这边是对数组里面的某个元素赋值, Vue 是可以侦测到的,Vue是通过监测 get, set 来得知数据是否更新,而数组的索引是没有 get、set

热心网友 时间:2022-05-14 19:56

公众号:【Vue社区】,整理了Vue和前端学习资料,及时更新最新前端优质文章
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
电脑lol突然很卡怎么办啊电脑玩lolfps低怎么解决 危化品仓库有什么设备 香港中文大学2021-2022在河北,重庆最低录取分数线 ChaCheer 洽洽 南瓜子 盐焗味 500g-适用对象 老闫家小粒香南瓜子-适用对象 洽洽盐焗味南瓜子-适用对象 盐焗南瓜子里有添加明矾吗 老街口盐焗味南瓜子500g*2袋量大优惠休闲零食 一天走多少步可以减肥每天走多少步可以减肥 肉炖土豆需要炖多久时间 急!我想知道三角型的性质。概念 如何阅读Vuejs源码,学习笔记 等边三角形怎么分成9个形状,大小都一样的三角形 淘宝上上传了东西怎么不见了? 为什么明明在我淘宝店铺发布的宝贝却没有在店铺显示出来 夏季如何制作既好吃又能解暑的绿豆糕? 夏天绿豆汤的做法 夏日特饮绿豆汤,煮绿豆汤有哪些小技巧? 绿豆的最佳吃法 绿豆汤如何做好吃(特别是夏天 夏天绿豆汤是必不可少的,在家怎么自己做绿豆汤? 炎炎夏日,绿豆汤怎么做更好吃 绿豆可以怎么吃呢? 不煮粥不做汤,绿豆有哪些好吃解馋的做法? 绿豆有几种吃法? 夏天绿豆汤怎么做好吃 你真的会正确临帖吗 绿豆除了熬粥,怎么做更好吃? 临摹临什么 什么是临帖? 初中几何点面线的重要知识点 初一下学期 知识点总结(三角形和三角形的证明 的知识要细致一些) 微商用的“笔记”是什么软件? 有下列说法:①有一个角为60°的等腰三角形是等边三角形; ②两条平行线之间的距离处处相等;③三边长 ReferenceError: Vue is not defined是什么意思? 相互平行的三角形可以得出什么结论 Github上有什么开源的vue+laravel网站代码吗 如图一,在Rt△ABC中,∠ACB=90°,∠A=30°,P为BC边上任意一点,点Q为AC边动点,分别以Cm、MQ为边做等 急需直线、射线、线段、平行线、线段垂直平分、角、三角形、四边形的性质、定义和判定。 我想学习前端,想问下前端从入门到进阶需要具备哪些知识? 三角形ABC为等边三角形,D为AB边上的中点。已知三角形BDE的面积为5平方厘米。求等边三角形ABC的面积 相交线与平行线所有涉及的性质和定理 初二数学内容 如何实现计算机毕业设计? 求解啊,只能用全等,等腰、等边三角形,角平分线,等角对等边,平行线的定义及性质,求出来的越多越好 平行四边形,三角形,梯形,等腰梯形的性质和识别方法 如图,等边三角形ABC,P是BC边上的一点,过C、P点分别作AB,AC的平行线,两线交于点 初中数学几何图形判定及性质(懂的来) 如图,△ABC, △DCE,△CEF都是正三角形, 且B,C,E,F在同一直线上,A,D,G也在同一直线上,设△ABC, △DCE,△CE 初一公式 初中数学的几何图形中,应如何添加辅助线?