用一行代码,快速填充一个数组
function fillArray(length, placeholder) {
return Array.apply(null, Array(length)).map(()=>placeholder)
}
然而用下面的语句却不可以
Array(length).map(()=>placeholder)
Array(length)返回的结果与预想不一样
检查Array(length)
的返回结果,发现其,是一个长度为length
的数组,从0
到length-1
都未定义。使用var arrWithHoles = Array(3)
与var arrWithHoles = [, , ,]
等效。而我们预想中这个数组应该是var arr = [undefined,undefined, undefined]
两者的差别好比是var foo = {0: undefined}; console.log(foo[0])
与var foo = {}; console.log(foo[0])
的差别
那些数组中未定义的索引,姑且称之为hole
使用Array.prototype.map
遍历一个带有hole的数组,map
方法会自动过滤hole。这是应该的,因为map
不知道未定义的索引是什么(不可能凭空猜想吧),它只知道遍历的数组有多长,已定义的索引是什么,哪怕这些索引的值是undefined
。
apply与map函数工作方式不同
Array内置遍历函数有些会跳过hole,比如forEach
,map
,有些会报错,比如reduce
,有些似乎没有影响,比如every
。
而Function.prototype.apply
的作用机制与Array内置函数不同。apply要求两个参数,第二个参数argsArray
必须是一个数组。在Array.apply(null, Array(length))
里,Array(length)应该经历了类似于如下的处理
var argsArray = Array(length)
var ret = []
var i
for (i = 0; i < argsArray.length; i++) {
ret[i] = argsArray[i]
}
所以Array.apply(null, Array(length))返回的结果是一个长度为length的数组,从0到length-1的值都为undefined。
map方法知道这个数组从0到length-1都有定义。虽然这些索引的值都是undefined,但是这不重要。重要的是map知道它应该处理这些索引,因为这些索引都被声明了,然后取它们的undefined值及其他信息,运行map函数,返回一个新的数组。
最后Array.apply(null, Array(length)).map(()=>placeholder)
返回的结果就是一个长度为length的数组,从0到length-1索引的值都为placeholder。完美!