问题来源:https://segmentfault.com/q/1010000015780995
问题描述:Vue检测数据的变动是通过Object.defineProperty实现的,所以无法监听数组的添加操作是可以理解的,因为是在构造函数中就已经为所有属性做了这个检测绑定操作。
但是官方的原文:由于 JavaScript 的限制, Vue 不能检测以下变动的数组:
当你利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如: vm.items.length = newLength
这句话是什么意思?我测试了下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循环中不做操作的话两者速度差不多
其次,我要说的是,我也不知道这个限制是什么 ("htmlcode">
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
可以看到会先运行一次set,然后数据更新,重新渲染页面,数组又是被遍历了两遍。
但是!!!数组确实变成响应式的了,也就是说js语法功能并不会限制数组的监测。
这里我们是用长度为3的数组测试的,当我把数组长度增加到9时
可以看到,运行了18次get,数组还是被遍历了两遍,点击某个元素同理,渲染的时候也是被遍历两次。
有了上面的实验,我的结论是数组在vue中是可以实现响应式更新的,但是不明白尤大是出于什么考虑,没有加入这一功能,希望有知道的大佬们不吝赐教
2018-07-27补充
github上提问了尤大
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]