之间究竟有什么区别:
Array(3)
// and
Array.apply(null, Array(3) )
第一个返回[undefined x 3]
,而第二个返回[undefined, undefined, undefined]
。第二个可以链接到Array.prototype.functions
,例如.map
,但第一个不是{{1}}。为什么呢?
答案 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