使用扩展语法创建一系列自然数

Ala*_*lan 5 javascript arrays iterator ecmascript-6

一方面,rangeES6 中缺乏与 Python 3 相当的东西是一个烦恼。另一方面,有很多解决方法。我的问题是为什么我尝试的一种解决方法实际上有效。为了显示:

[...Array(10).keys()];
Run Code Online (Sandbox Code Playgroud)

如果我发现这个神秘的原因并不明显,请注意,Array(10).keys()至少表面上是空的。

我知道这会浪费地创建两个数组,就像大多数流行的解决方法一样,并且(以创建生成器函数为代价)使用生成器可以避免这种情况。例如,

[...(function*(){let i = 0; while(i<10) yield i++;})()];
Run Code Online (Sandbox Code Playgroud)

我的问题只是关于为什么第一个解决方法会产生所需的结果。

编辑:

从答案来看,有人认为,评价Array(10)等同于评价Array.apply(null,Array(10))。他们不是。例如,.hasOwnProperty(0)false针对前者,但true针对后者。然而,我愿意被说服,他们在某些重要的方面是相同的,因为我在某些关键点上显然缺乏理解。我怀疑答案是迭代键的结果是由length两者共享的属性决定的,而不是由已定义的实际数组索引决定的。如果是这样,我想知道这种行为是否正常。

Li3*_*357 5

Array#keys返回一个Array 迭代器。然后,扩展语法通过访问迭代器中的下一个值来完全耗尽该迭代器,直到没有更多值为止。然后它从迭代器中收集所有值并将它们传播到一个新数组中。

Array(10)创建一个数组外来对象,它没有任何实际的整数索引键,而只是一个length属性 - 所以它会“空”,但Array(10).keys()实际上不是。事实上, usingArray#keys 不依赖于实际元素,只依赖于 length 属性。内部操作CreateArrayIterator通过内在%ArrayIteratorPrototype% 对象创建迭代器,从数组创建键迭代器。查看%ArrayIteratorPrototype%.next(),您会发现使用了数组的长度。因为Array#keys索引不断递增,直到达到数组的长度。这就是迭代器的创建方式,该迭代器为您提供数组的所有键,而无需实际上首先拥有所述整数键。


如果您对抽象步骤感到好奇,请参阅ECMAScript 语言规范的第 12.2.5.2 节 ArrayAcculumationSpreadElement : ... AssignmentExpression ,特别是概述了逐步执行与扩展语法结合使用的迭代器的过程的产生式。

要查看将这些值收集到新数组中的抽象步骤,请参阅第 12.2.5.3 节评估。具体来说,ArrayLiteral : [ ElementList ]生产属于生产[...Array.keys()]范畴。执行上述 ArrayAcculumation 过程,该过程聚合迭代器中的迭代并将它们设置到新数组中。