数组的响应式限制
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:vm.items.length = newLength
以上是 Vue 2.x 官方文档里的说明,但是这到底是因为什么限制呢?
数组的 length
数组的length
属性是不可配置、不可枚举的。因为该项限制,导致无法通过Object.defineProperty
给数组的length
属性添加getter
和setter
。
const array = [];
Object.getOwnPropertyDescriptor(a, 'length')
// 结果
// {
// configurable: false
// enumerable: false
// value: 0
// writable: true
// }
Object.defineProperty(array, 'length', {
get() {},
set() {}
})
// Uncaught TypeError: Cannot redefine property: length
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
数组项
数组项是可以通过Object.defineProperty
设置getter
和setter
的,但是为什么 Vue 也不允许基于索引修改数组项呢?
- 动态添加的数组项无法通过
Object.defineProperty
设置getter
和setter
,而数组的长度是可变的,会经常添加新数组项和删除数组项。 - 当数组较大时,给数组的每一项都设置
getter
和setter
,效率太低性能太差。 - 当数组的
length
为5
时,未必索引就有4
,索引可能不存在,就没法setter
。
针对最后一点,其前提是假设给数组的每个元素设置getter
和setter
时,是通过Object.keys()
来获取数组的所有属性的;若是for (let i = 0; i < array.length; i++)
来设置getter
和setter
,倒是可以,但是这样效率太低性能太差。
const array = [];
array[5] = 5;
console.log(Object.keys(array)) // ['5']
1
2
3
4
5
2
3
4
5