我正在寻找下面的任何替代方法来创建一个包含 1 到 N 的 JavaScript 数组,其中 N 仅在运行时已知。
var foo = [];
for (var i = 1; i <= N; i++) {
foo.push(i);
}
对我而言,感觉应该有一种没有循环的方法。
你可以这样做:
var N = 10;
Array.apply(null, {length: N}).map(Number.call, Number)
结果:[0,1,2,3,4,5,6,7,8,9]
或随机值:
Array.apply(null, {length: N}).map(Function.call, Math.random)
结果:[0.7082694901619107,0.95702225909214467,0.8586748542729765,0.8653848143294454,0.008339877473190427,0.991756622605026,0.8133423360995948,0.8377588465809822,0.5577575915958732,0.163636514581783035]
首先,请注意Number.call(undefined, N)
等于Number(N)
, Number.call(undefined, N)
返回N
我们稍后会使用这个事实。
Array.apply(null, [undefined, undefined, undefined])
等效于Array(undefined, undefined, undefined)
,它生成一个三元素数组并为每个元素指定undefined
。
你如何将它推广到N 个元素?考虑一下Array()
工作原理,如下所示:
function Array() {
if ( arguments.length == 1 &&
'number' === typeof arguments[0] &&
arguments[0] >= 0 && arguments &&
arguments[0] < 1 << 32 ) {
return [ … ]; // array of length arguments[0], generated by native code
}
var a = [];
for (var i = 0; i < arguments.length; i++) {
a.push(arguments[i]);
}
return a;
}
由于 ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)
也接受鸭子类型的数组对象作为其第二个参数。如果我们调用Array.apply(null, { length: N })
,那么它将执行
function Array() {
var a = [];
for (var i = 0; i < /* arguments.length = */ N; i++) {
a.push(/* arguments[i] = */ undefined);
}
return a;
}
现在我们有一个N元素数组,每个元素都设置为undefined
。当我们调用.map(callback, thisArg)
时,每个元素都将被设置为callback.call(thisArg, element, index, array)
。因此, [undefined, undefined, …, undefined].map(Number.call, Number)
会将每个元素映射到(Number.call).call(Number, undefined, index, array)
,这与Number.call(undefined, index, array)
相同Number.call(undefined, index, array)
,正如我们之前观察到的那样,它是对index
评估。这样就完成了元素与索引相同的数组。
为什么要经历Array.apply(null, {length: N})
而不仅仅是Array(N)
的麻烦?毕竟,两个表达式都会产生一个未定义元素的N元素数组。不同之处在于,在前一个表达式中,每个元素都显式设置为 undefined,而在后者中,每个元素都从未设置过。根据.map()
的文档:
仅为已分配值的数组的索引调用
callback
; 对于已删除的索引或从未分配过值的索引,不会调用它。
因此, Array(N)
不足; Array(N).map(Number.call, Number)
将导致长度为N的未初始化数组。
由于此技术依赖于 ECMAScript 5 中指定的Function.prototype.apply()
行为,因此它不适用于 ECMAS 和 Internet Explorer 9 之类的 ECMAScript 前 5 浏览器。