Puedes hacerlo:
var N = 10;
Array.apply(null, {length: N}).map(Number.call, Number)
resultado: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
o con valores aleatorios:
Array.apply(null, {length: N}).map(Function.call, Math.random)
resultado: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915954532454
Explicación
Primero, tenga en cuenta que Number.call(undefined, N)
es equivalente a Number(N)
, que simplemente regresa N
. Usaremos ese hecho más tarde.
Array.apply(null, [undefined, undefined, undefined])
es equivalente a Array(undefined, undefined, undefined)
, que produce una matriz de tres elementos y se asigna undefined
a cada elemento.
¿Cómo puedes generalizar eso a N elementos? Considere cómo Array()
funciona, que es algo como esto:
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;
}
Desde ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)
también acepta un objeto tipo matriz tipo pato como su segundo parámetro. Si invocamos Array.apply(null, { length: N })
, se ejecutará
function Array() {
var a = [];
for (var i = 0; i < /* arguments.length = */ N; i++) {
a.push(/* arguments[i] = */ undefined);
}
return a;
}
Ahora tenemos una matriz de elementos N , con cada elemento establecido en undefined
. Cuando lo invoquemos .map(callback, thisArg)
, cada elemento se establecerá en el resultado de callback.call(thisArg, element, index, array)
. Por [undefined, undefined, …, undefined].map(Number.call, Number)
lo tanto, correlacionaría cada elemento con (Number.call).call(Number, undefined, index, array)
, que es lo mismo Number.call(undefined, index, array)
que, como observamos anteriormente, se evalúa como index
. Eso completa la matriz cuyos elementos son los mismos que su índice.
¿Por qué pasar por la molestia de en Array.apply(null, {length: N})
lugar de solo Array(N)
? Después de todo, ambas expresiones resultarían en una matriz de elementos N de elementos indefinidos. La diferencia es que en la primera expresión, cada elemento se establece explícitamente en indefinido, mientras que en la última, cada elemento nunca se estableció. De acuerdo con la documentación de .map()
:
callback
se invoca solo para índices de la matriz que tienen valores asignados; no se invoca para índices que se han eliminado o a los que nunca se les han asignado valores.
Por lo tanto, Array(N)
es insuficiente; Array(N).map(Number.call, Number)
resultaría en una matriz sin inicializar de longitud N .
Compatibilidad
Dado que esta técnica se basa en el comportamiento Function.prototype.apply()
especificado en ECMAScript 5, no funcionará en navegadores anteriores a ECMAScript 5 como Chrome 14 e Internet Explorer 9.