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>)
这个是完全不同的。它有两种情况。在初始化时,使用ArrayCreate(0, proto) 创建一个数组对象,就像您使用new Array() 一样。我们仍然有一个论点可以使用。
如果参数是 非数字 值,则效果与第 2 点相同。此参数被添加到构造对象中(如 .push() 操作。所以 new Array('hello')或new Array('10') 为您提供带有.length = 1 的数组对象
现在,当你给出一个 numeric 参数 new Array(10) 时,情况就大不相同了,它在 Chrome 中给出了 [undefined x 10]。为什么?因为当参数为数字(且有效)时,将调用此函数:Set(O,P,V,Throw)。这个“神奇”函数将对象O 的属性P 设置为值V。 (Throw 是一个标志,表示“throw error or not?”问题)。
如果参数是一个长度,set(<constructed array>, 'length', <argument>, true) 正在被执行。因此.length 属性返回参数值,而内存中没有保留任何内容。最终结果:你有一个带有假的.length 属性的对象......这样做的副作用是使用.push 将一个元素添加到第10 个索引(如果.length 是10)。现在您有一个包含 11 个元素的数组:10 个“空”插槽和一个您刚刚推送的元素。
那么浏览器如何处理带有“假”.length 属性的数组呢?他们无法正确地迭代它。因此它们提供了一种故障保护方式:显示“有 10 个元素但为空”,就像 chrome 使用 [undefined x 10] 或 firefox:Array [ <10 empty slots>]
如果您问我为什么在规范中将其标准化,那么我会回答“我不知道”。这是 ECMAScript 中标准化的最奇怪的决定之一(在我遇到的其他决定中)。