以下Array初始化语法实际创建了什么?

时间:2017-07-04 14:07:56

标签: javascript

以下内容实际创建了什么?

我问,因为它无法使用Array#foreach进行枚举,并且在Chrome控制台中以[undefined x 10]表示(误导性?)。

const arr = new Array(10);

3 个答案:

答案 0 :(得分:3)

Array对象有三种不同的构造函数:

  1. new Array()
  2. new Array(<multiple arguments)
  3. new Array(<one argument>)(由于性质而放在最后 - 见进一步说明)
  4. 构造函数的行为取决于提供给该构造函数的参数。在构造函数操作期间,所有这三个操作都使用ArrayCreate。从链接:

      

    带有参数长度(正整数)和可选参数proto的抽象操作ArrayCreate用于指定新的Array异物对象的创建。

    此函数接受两个参数:len(长度)和proto,用于创建数组对象。 (我不会在这里更深入,因为它会更复杂)。在这种情况下,len参数更为重要。当我们单独查看构造函数时,您有

    new Array()

    这里,一个对象由ArrayCreate(0, proto)构成,因此是一个带.length = 0的空数组。

    new Array(<multiple arguments>)

    这里,对象由ArrayCreate(#of args, proto)构成。如果你提供3个参数,那么你得到一个.length = 3的数组。然后使用提供的参数填充此数组。你给5个参数吗?你得到.length = 5。所以.length属性取决于参数的数量。

    new Array(<one argument>)

    这个是完全不同的。它有两个案例。在init,使用ArrayCreate(0, proto)创建一个数组对象,就像使用new Array()一样。我们仍然有一个论据可供使用。

    如果参数是非数字值,则效果与第2点相同。此参数将添加到构造对象(如.push()操作。所以{ {1}}或new Array('hello')为您提供了一个new Array('10')

    的数组对象

    现在,当您提供数字参数.length = 1时,情况会有所不同,这会在Chrome new Array(10)中提供。为什么?因为当参数是数字(并且有效)时,将调用此函数:Set(O,P,V,Throw)。这个“魔术”函数使用值[undefined x 10]设置对象P的属性O。 (V是一个标志,表示“抛出错误与否?”问题)。

    如果参数是长度,则正在执行Throw。因此set(<constructed array>, 'length', <argument>, true)属性返回参数值,而内存中没有任何内容。最终结果:你有一个带有假.length属性的对象......这样做的副作用是使用.length向第10个索引添加一个元素(如果.push为10) 。现在你有一个包含11个元素的数组:10个“空”插槽和一个你刚才推动的元素。

    那么浏览器对具有“假”.length属性的数组做了什么?他们无法正确迭代它。因此,它们提供了一种故障安全方式:显示“有10个元素但是为空”,例如chrome与.length或firefox:[undefined x 10]

    如果你问我为什么在规范中标准化,那么我会回答“我不知道”。这是ECMAScript中标准化的最奇怪的决定之一(我遇到过的其中之一)。

答案 1 :(得分:1)

以下两个片段是等效的:

const arr = new Array(10)

const arr = [,,,,,,,,,,]

可以在这里证明:

&#13;
&#13;
const arr1 = new Array(10)
const arr2 = [,,,,,,,,,,]

let empty1 = true

for (let index = 0; empty1 && index < arr1.length; index++) {
  if (arr1.hasOwnProperty(index)) {
    empty1 = false
  }
}

let empty2 = true

for (let index = 0; empty1 && index < arr2.length; index++) {
  if (arr2.hasOwnProperty(index)) {
    empty2 = false
  }
}

console.log(empty1)
console.log(empty2)
&#13;
&#13;
&#13;

这意味着对于来自[0, length - 1]的所有索引,它们实际上并不存在于数组中,因为arr.hasOwnProperty(index)false。这与此示例不同:

const arr = new Array(10).fill()

在这里演示:

&#13;
&#13;
const arr = new Array(10).fill()

console.log(arr.every((_, index) => arr.hasOwnProperty(index)))
&#13;
&#13;
&#13;

因此,如果要使用undefined初始化构造的数组中的每个索引,只需调用.fill()而不带任何参数。

答案 2 :(得分:0)

Array构造函数在提供单个整数值时会创建一个Array实例,并将length own-property设置为该值。

浏览器等主机环境可以选择按照自己的选择进行渲染。 V8选择具有误导性的[undefined x 10],因为它暗示在有序序列中有十个预定义undefined值的实例。

事实并非如此。

Array#foreachArray#map使用可枚举的整数索引和length own-property值来枚举数组的值。

由于此特定Array构造函数语法未初始化Array对象上的任何整数属性,因此无法枚举以此方式初始化的Array

我只能假设这种语法存在,以启用依赖于length实例的Array自身属性的代码模式,而不需要初始化任何键或值。