添加新属性时,为什么不更改数组的长度?

时间:2015-04-29 04:47:54

标签: javascript arrays



var arr = ["Hello", "There", 123, 456, {
    show: function (value) {
        alert(value);
    }
}];
arr[4].show(arr[0]);
arr["Hello"] = {
    damn: function () {
        alert("What's happening yo !");
    }
}
arr.Hello.damn();
alert("Arr length is: " + arr.length);




4 个答案:

答案 0 :(得分:9)

引用ECMA脚本5规范Array Objects

  

当且仅当P等于ToString(ToUint32(P))并且P不相等时,属性名称ToUint32(P)(以String值的形式)是一个数组索引到2 32 -1。

由于Hello无效,根据上面的定义,它不被视为数组索引,而是普通属性。

引用MDN' Relationship between length and numerical properties section

  

当属性是有效数组索引时在JavaScript数组上设置属性并且该索引超出数组的当前边界时,引擎将更新数组的长度属性相应

因此,仅当属性是有效的数组索引时,才会调整length属性。

在您的情况下,您刚刚在数组对象上创建了一个新属性Hello

注意:只有数字属性才会用于Array的所有原型函数,例如forEachmap

例如,当与forEach一起使用时,显示的数组

arr.forEach(function(currentItem, index) {
    console.log(currentItem, index);
})

会打印

Hello 0
There 1
123 2
456 3
{ show: [Function] } 4

即使密钥列表显示Hello

console.log(Object.keys(arr));
// [ '0', '1', '2', '3', '4', 'Hello' ]

这是因为Array来自Object

console.log(arr instanceof Object);
// true

Hello是数组对象的有效键,但不是有效的数组索引。因此,当您将数组视为对象时,Hello将包含在键中,但特定于数组的函数将仅包含数字属性。

答案 1 :(得分:1)

这是因为length仅在将新的数字属性添加到数组as required by the specification时更新:

  

此Array对象的length属性是一个data属性,其值始终在数值上大于名称为数组索引的每个deletable属性的名称。

数组索引is specified to be

  

当且仅当ToString(ToUint32(P))等于P且ToUint32(P)不等于232-1时,属性名P(以String值的形式)是数组索引。

但是,数组也是对象 - 因此您可以向数组添加非数组索引属性,就像您可以向任何其他JavaScript对象添加属性一样(这就是为什么您的示例也不会抛出)。

答案 2 :(得分:0)

javascript长度计算为1+(最高数字索引元素)。因此,当您添加arr['Hello']时,您只需添加一个字符串索引,在计算数组长度时不会将其考虑在内。

这是ECMAScript 5.1

中描述的数组长度属性的实际定义
  

每个Array对象都有一个length属性,其值始终为a   非负整数小于2 32 。 length属性的值是   在数字上大于名称为a的每个属性的名称   数组索引;每当创建Array对象的属性时   更改后,其他属性会根据需要进行调整以维持此状态   不变的。具体来说,每当添加名称为的属性时   数组索引,如果需要,将更改长度属性为1   超过该数组索引的数值;无论什么时候   length属性已更改,每个属性的名称都是数组   其值不小于新长度的索引是自动的   删除。此约束仅适用于Array的自身属性   对象并且不受可能的长度或数组索引属性的影响   继承自原型。

答案 3 :(得分:0)

当你写:

  

ARR ["你好"] = ...

您正在创建与arr数组对象关联的新对象,该对象不会影响arr的长度。

您可以通过写作来实现相同的效果:

  

arr.Hello = ...