Array.apply(null,Array(x))和Array(x)之间的区别

时间:2015-02-09 18:16:24

标签: javascript

之间究竟有什么区别:

Array(3)
// and
Array.apply(null, Array(3) )

第一个返回[undefined x 3],而第二个返回[undefined, undefined, undefined]。第二个可以链接到Array.prototype.functions,例如.map,但第一个不是{{1}}。为什么呢?

5 个答案:

答案 0 :(得分:19)

存在差异,非常重要。

Array构造函数 要么 接受一个数字,给出数组的长度,并创建一个带有“空”索引的数组,或者更多正确设置了长度,但数组实际上并不包含任何内容

Array(3); // creates [], with a length of 3

当使用数字作为唯一参数调用数组构造函数时,您将创建一个空的数组,并且无法使用常用的Array方法进行迭代。

... Array构造函数接受多个参数,而创建一个数组,其中每个参数都是数组中的值

Array(1,2,3); // creates an array [1,2,3] etc.

当你打电话给这个

Array.apply(null, Array(3) )

它变得更有趣了。

apply接受this值作为第一个参数,因为它在这里没用,所以设置为null

有趣的部分是第二个参数,其中传入一个空数组。
由于apply接受一个数组,它就像调用

Array(undefined, undefined, undefined);

并创建一个包含三个非空的索引的数组,但实际上将值设置为undefined,这就是为什么可以迭代它。

<强> TL; DR
主要区别在于Array(3)创建了一个包含三个空索引的数组。实际上,它们并不存在,数组的长度只有3

使用apply将带有空索引的数组传递给Array构造函数与执行Array(undefined, undefined, undefined);相同,后者创建一个包含三个undefined索引的数组,{{1}实际上是一个值,所以它不像第一个例子那样是空的。

undefined这样的数组方法只能迭代实际值,而不是空索引。

答案 1 :(得分:13)

.map() API不会迭代完全未初始化的数组元素。当您使用new Array(n)构造函数创建一个新数组时,您将得到一个数组,其中包含您要求的.length但不存在的元素将被.map()等方法跳过。

表达式Array.apply(null, Array(9))使用undefined显式填充新创建的数组实例,但这已经足够好了。诀窍是in运算符是否会报告数组包含给定索引处的元素。那就是:

var a = new Array(9);
alert(2 in a); // alerts "false"

那是因为数组中的位置2上确实没有元素。但是:

var a = Array.apply(null, Array(9));
alert(2 in a); // alerts "true"

对Array构造函数的外部调用将显式填充元素。

答案 2 :(得分:4)

这是 apply 的工作原理。当你这样做时:

new Array(9)

创建一个长度为9的空数组。 map 不会访问不存在的成员,所以什么都不做。但是,apply使用CreateListFromArrayLike将数组转换为列表,因此它将以前为空的数组转换为参数列表,如:

[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];

传递给 Array 以创建一个包含9个成员的数组,所有成员的值均为 undefined 。所以现在地图将全部访问它们。

顺便说一下,ECMAScript 2015有Array.prototype.fill这个(也见MDN)所以你可以这样做:

Array(9).fill(0);

答案 3 :(得分:0)

因为第一个数组不具有有序属性arr[0] === undefined而第二个数组没有。像forEach和map这样的数组函数将从0迭代到数组的长度 - 1并且缺少第一个属性的顺序是一个问题。第二个版本产生一个具有正确排序的数组,即

arr = Array.apply(null, Array(3));
arr[0] === undefined //true
arr[1] === undefined //true
//etc.

您注意到的第一个版本并不是。此外,将new添加到第一个版本将无法使其正常工作。

答案 4 :(得分:0)

在第一种情况下,您只有一个操作

  

Array(3)

它创建一个带有三个空插槽的数组。不是具有三个未定义值的数组,而是完全为空。

第二种情况

  

Array.apply(null,Array(3))

我们可以将其扩展到三个操作:

  • 首先:Array(3)-您将获得一个带有3个空插槽的数组;

  • 秒:Array(3)通过Function.prototype.apply()函数扩展为传递给Array()函数的3个参数。在此阶段,给定数组中的3个空插槽通过apply()转换为3个未定义的值(看起来,如果apply()看到一个空插槽,它将自动将其变为任何稀疏数组中的undefined)。

  • 第三:我们得到一个Array(未定义,未定义,未定义)。这将为我们提供一个具有3个未定义(非空)值的数组。

由于现在有3个未定义但没有空的插槽,因此可以将它们与map()函数一起使用。

请注意,不仅Function.prototype.apply()具有通过这种方式分解数组的行为。您也可以在ECMAScript 6中通过“ ...”-传播算子来完成此操作。

Array(...new Array(3));

这还将返回一个带有3个未定义且可以分别映射槽的数组。

在这里,我给出更详细的解释。 https://stackoverflow.com/a/56814230/11715665