Puoi farlo:
var N = 10;
Array.apply(null, {length: N}).map(Number.call, Number)
risultato: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
o con valori casuali:
Array.apply(null, {length: N}).map(Function.call, Math.random)
risultato: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.557757591535363245 0.117
Spiegazione
Innanzitutto, nota che Number.call(undefined, N)
equivale a Number(N)
, che ritorna N
. Lo useremo più tardi.
Array.apply(null, [undefined, undefined, undefined])
è equivalente a Array(undefined, undefined, undefined)
, che produce un array di tre elementi e assegna undefined
a ciascun elemento.
Come puoi generalizzare questo a N elementi? Considera come Array()
funziona, che funziona in questo modo:
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;
}
Dal momento che ECMAScript 5 , Function.prototype.apply(thisArg, argsArray)
accetta anche un oggetto simile a una matrice tipo duck come secondo parametro. Se invochiamo Array.apply(null, { length: N })
, verrà eseguito
function Array() {
var a = [];
for (var i = 0; i < /* arguments.length = */ N; i++) {
a.push(/* arguments[i] = */ undefined);
}
return a;
}
Ora abbiamo un array N -element, con ogni elemento impostato su undefined
. Quando lo chiamiamo .map(callback, thisArg)
, ogni elemento verrà impostato sul risultato di callback.call(thisArg, element, index, array)
. Pertanto, [undefined, undefined, …, undefined].map(Number.call, Number)
mapperebbe ogni elemento a (Number.call).call(Number, undefined, index, array)
, che è lo stesso di Number.call(undefined, index, array)
, che, come abbiamo osservato in precedenza, valuta index
. Ciò completa l'array i cui elementi sono uguali al loro indice.
Perché affrontare il problema Array.apply(null, {length: N})
invece che solo Array(N)
? Dopotutto, entrambe le espressioni risulterebbero in una matrice N- elemento di elementi indefiniti. La differenza è che nella prima espressione ogni elemento è esplicitamente impostato su indefinito, mentre nella seconda ogni elemento non è mai stato impostato. Secondo la documentazione di .map()
:
callback
viene invocato solo per gli indici dell'array a cui sono stati assegnati valori; non viene invocato per gli indici che sono stati eliminati o ai quali non sono mai stati assegnati valori.
Pertanto, Array(N)
è insufficiente; Array(N).map(Number.call, Number)
comporterebbe un array inizializzato di lunghezza N .
Compatibilità
Poiché questa tecnica si basa sul comportamento Function.prototype.apply()
specificato in ECMAScript 5, non funzionerà nei browser pre-ECMAScript 5 come Chrome 14 e Internet Explorer 9.