以下内容实际创建了什么?
我问,因为它无法使用Array#foreach
进行枚举,并且在Chrome控制台中以[undefined x 10]
表示(误导性?)。
const arr = new Array(10);
答案 0 :(得分:3)
Array
对象有三种不同的构造函数:
new Array()
new Array(<multiple arguments)
new Array(<one argument>)
(由于性质而放在最后 - 见进一步说明)构造函数的行为取决于提供给该构造函数的参数。在构造函数操作期间,所有这三个操作都使用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 = [,,,,,,,,,,]
可以在这里证明:
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;
这意味着对于来自[0, length - 1]
的所有索引,它们实际上并不存在于数组中,因为arr.hasOwnProperty(index)
是false
。这与此示例不同:
const arr = new Array(10).fill()
在这里演示:
const arr = new Array(10).fill()
console.log(arr.every((_, index) => arr.hasOwnProperty(index)))
&#13;
因此,如果要使用undefined
初始化构造的数组中的每个索引,只需调用.fill()
而不带任何参数。
答案 2 :(得分:0)
Array
构造函数在提供单个整数值时会创建一个Array
实例,并将length
own-property设置为该值。
浏览器等主机环境可以选择按照自己的选择进行渲染。 V8选择具有误导性的[undefined x 10]
,因为它暗示在有序序列中有十个预定义undefined
值的实例。
事实并非如此。
Array#foreach,Array#map使用可枚举的整数索引和length
own-property值来枚举数组的值。
由于此特定Array
构造函数语法未初始化Array
对象上的任何整数属性,因此无法枚举以此方式初始化的Array
。
我只能假设这种语法存在,以启用依赖于length
实例的Array
自身属性的代码模式,而不需要初始化任何键或值。