arr = Array(10).fill(false)
arr[-2] = true
console.log(arr)
[false, false, false, false, false, false, false, false, false, false, -2: true]
console.log(arr.length) // 10
我很惊讶于在数组的负索引中添加一个元素会在数组中添加一个键值对。而且,数组的长度也没有增加?
arr = Array(10).fill(false)
arr[-2] = true
console.log(arr)
[false, false, false, false, false, false, false, false, false, false, -2: true]
console.log(arr.length) // 10
我很惊讶于在数组的负索引中添加一个元素会在数组中添加一个键值对。而且,数组的长度也没有增加?
let a = [];
a[0] = 9;
a[-1] = 10; // will act as key "-1" added to object a with value 10
console.log(a); //[9]
console.log(a["-1"]); //10
console.log("Length of array " + a.length); // 1, key "-1" will not contribute to the lenght of an array
从MDN中提取定义Array.length
数组类型的对象的长度属性设置或返回该数组中元素的数量。该值是一个无符号的32位整数,始终比数组中最高索引大。
它仅计算从基于0的索引到最高数字的长度。 因此,任何无效或负数都将被忽略。 因此,长度实际上不是您在屏幕上看到的元素数量。
与length
属性的关系 MDN
最好的方法是简单地说明在 JavaScript 中不存在负索引。
为了完整起见,上述参考资料已经解释了这一点:
整数索引是一个字符串值属性键,它是一个规范化的数字字符串(参见7.1.16),其数值为+0或≤253-1的正整数。数组索引是一个整数索引,其数值i在范围+0≤i<232-1内。
然而,你也可以使用JavaScript迭代器来证明这一点。每个Javascript数组都有两个方法(返回迭代器)来跟踪数组中的值和键。它们分别是array.values()
和array.keys()
方法。
因此,简单地遍历一个数组的values和keys就足以证明任何添加的“负索引”不是数组中的键值对,而只是一个属性。
let a = [1, 2, 3, 4];
a[-1] = 5;
let valueIterator = a.values();
let keyIterator = a.keys();
let valueCount = keyCount = 0;
while(!valueIterator.next().done) {
valueCount++;
}
while(!keyIterator.next().done) {
keyCount++;
}
console.log("Number of values: " + valueCount); // 4
console.log("Number of keys: " + keyCount); // 4
仅为了明确这是标准行为而不是懒惰开发人员的工作,以下是一些关于数组对象的官方规范:
Assert: IsPropertyKey(P) is true.
If P is "length", then
Return ? ArraySetLength(A, Desc).
Else if P is an array index, then
Let oldLenDesc be OrdinaryGetOwnProperty(A, "length").
Assert: oldLenDesc will never be undefined or an accessor descriptor because Array objects are created with length data property that cannot be deleted or reconfigured.
Let oldLen be oldLenDesc.[[Value]].
Let index be ! ToUint32(P).
If index ≥ oldLen and oldLenDesc.[[Writable]] is false, return false.
Let succeeded be ! OrdinaryDefineOwnProperty(A, P, Desc).
If succeeded is false, return false.
If index ≥ oldLen, then
Set oldLenDesc.[[Value]] to index + 1.
Let succeeded be OrdinaryDefineOwnProperty(A, "length", oldLenDesc).
Assert: succeeded is true.
Return true.
Return OrdinaryDefineOwnProperty(A, P, Desc).
因此,如果键与数组索引定义匹配,则数组将将其视为数组索引,该定义如下:
整数索引是一个字符串值属性键,它是一个规范化的数字字符串(参见7.1.16),其数字值为+0或≤253-1的正整数。数组索引是一个整数索引,其数字值i在范围+0≤i < 232-1内。
否则,它将把键视为普通属性。
来源:http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf