在数组的负索引中添加一个元素?

3
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

我很惊讶于在数组的负索引中添加一个元素会在数组中添加一个键值对。而且,数组的长度也没有增加?


你可以给数组分配任意属性,由于它不是数组的真正索引(负索引不像索引一样),因此数组长度保持不变。 - Rajith Thennakoon
4个回答

3
数组是按数值索引的,但棘手的是它们也是可以添加字符串键/属性的对象(但这些不计入数组的长度):
数组中的索引从0开始,即它们可以是正数。
当您尝试访问数组中的负索引,例如a[-1]时,它将作为键,并且-1将存储为数组中的“-1”键,该键也是一个对象。但它不会计入数组的长度,只有数值索引会计入数组的长度。在JavaScript中,您可以将数组称为对象的子类型。

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

我建议您阅读这篇文章

3

从MDN中提取定义Array.length

数组类型的对象的长度属性设置或返回该数组中元素的数量。该值是一个无符号的32位整数,始终比数组中最高索引大。

它仅计算从基于0的索引到最高数字的长度。 因此,任何无效或负数都将被忽略。 因此,长度实际上不是您在屏幕上看到的元素数量。

length属性的关系 MDN

如果传递给Array构造函数的唯一参数是介于0和232-1(含)之间的整数,则返回一个新的JavaScript数组,其length属性设置为该数字(注意:这意味着一个由arrayLength个空插槽组成的数组,而不是具有实际未定义值的插槽)。如果参数是任何其他数字,则会抛出RangeError异常。 数组不能使用字符串作为元素索引(如关联数组),但必须使用整数。使用方括号表示法(或点表示法)进行非整数的设置或访问不会设置或检索数组列表本身中的元素,而是将设置或访问与该数组的对象属性集合相关联的变量。数组的对象属性和数组元素列表是分开的,不能将数组的遍历和变异操作应用于这些命名属性。 此处说明了设置“值”和“属性”的区别。在数组的有效范围之外设置的任何内容都被视为“属性”,就像其他任何对象一样。

0

最好的方法是简单地说明在 JavaScript 中不存在负索引

为了完整起见,上述参考资料已经解释了这一点:

整数索引是一个字符串值属性键,它是一个规范化的数字字符串(参见7.1.16),其数值为+0或≤253-1的正整数。数组索引是一个整数索引,其数值i在范围+0≤i<232-1内。

然而,你也可以使用JavaScript迭代器来证明这一点。每个Javascript数组都有两个方法(返回迭代器)来跟踪数组中的值和键。它们分别是array.values()array.keys()方法。

因此,简单地遍历一个数组的valueskeys就足以证明任何添加的“负索引”不是数组中的键值对,而只是一个属性

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


0

仅为了明确这是标准行为而不是懒惰开发人员的工作,以下是一些关于数组对象的官方规范:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接