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限制,我想知道这个限制是什么内容?各位大大帮我解决下这个问题,感谢万分
我最近刚好写过 Vue 的 Observer 部分源码分析博客
强答一波...
并不是说 JS 不能支持响应式数组,没有这种限制,而是一般开发者使用数组与使用对象的方法有区别。数组在 JS 中常被当作栈,队列,集合等数据结构的实现方式,会储存批量的数据以待遍历。并且 runtime 对对象与数组的优化也有所不同。
所以对数组的处理需要特化出来以提高性能。
Vue 中是通过对每个键设置 getter/setter 来实现响应式的,开发者使用数组,目的往往是遍历,此时调用 getter 开销太大了,所以 Vue 不在数组每个键上设置,而是在数组上定义
__ob__
,并且替换了 push 等等能够影响原数组的原型方法。至于 length 的问题,你用 Object.keys() 或者 Object.getOwnPropertyNames() 就能获得所有键的名字,前者是所有自有可枚举的,后者是所有自有的,不需要用 length 。
从源码可以清晰看到,Vue 跳过了对数组每个键设置响应式的过程,而是直接对值进行递归设置响应式
而且楼主你造吗?Vue 使用 $watch('arr') 是可以监听多维数组的,Vue 对普通对象和数组的设置情况是差异很大的。
另外还有就是楼上有人贴图
这里面的$set支持设置数组+响应式非数字键,Vue确实是这么支持的,然而!!如果在初始化时data里这么干,Vue会忽略非数字键的,不会变响应式,它这是行为不一致!对它使用watch,直接修改它不会变,但修改数组就会触发。
我早给Vue提issue了,但他们一直不理我。
https://github.com/vuejs/vue/...
欢迎阅读我博客Vue Observer源码分析,写得非常详细。
https://segmentfault.com/a/11...