Perché Array.apply (null, ) agisce in modo incoerente quando si tratta di array sparsi?

Recentemente ho scoperto il seguente snippet di codice su SO per aiutare a popolare rapidamente un array con valori predefiniti:

Array.apply(null, new Array(3)).map(function() {return 0;}); 

Dato il comportamento del costruttore Array e del metodo apply, lo snippet precedente può anche essere riscritto come tale:

 Array.apply(null, [undefined, undefined, undefined]).map(function() {return 0;}); 

Questa tecnica è utile anche quando si tratta di array sparsi che si desidera popolare con valori predefiniti:

 var sparseArr = [3,,,4,1,,], denseArr = Array.apply(null, sparseArr).map(function(e) { return e === undefined ? 0 : e; }); // denseArr = [3,0,0,4,1,0] 

Comunque è in ciò che sorgono due stranezze:

  1. Se il termine finale di sparseArr non è definito, tale termine non viene mappato in denseArr
  2. Se sparseArr contiene solo un singolo termine (ad es. sparseArr = [1] ) o un singolo termine seguito da un singolo termine finale indefinito (es. sparseArr = [1,] ), il denseArr risultante equivale a [undefined x 1]

Qualcuno può spiegare questo comportamento?

new Array(3) […] può anche essere riscritto come [undefined, undefined, undefined]

No – come appena visto, il costruttore di array crea array sparsi quindi dovrebbe essere riscritto come [,,,] .

Se il termine finale di sparseArr non è definito

No. Ti stai dimenticando dei commmenti finali, che sono facoltativi poiché EcmaScript 5. In realtà [1] è solo equivalente a [1,] (entrambi hanno una lunghezza di 1 ).

Per ottenere “slot” sparse, dovrai aggiungere una virgola aggiuntiva:

 [] // empty array [,] // empty array [,,] // [undefined x 1] [,,,] // [undefined x 2] 

Se sparseArr contiene solo un singolo termine, il denseArr risultante denseArr uguale a [undefined x N]

Considera cosa significa chiamare il metodo apply :

 Array.apply(null, [3,,4,1]) ≡ Array(3, undefined, 4, 1) Array.apply(null, [3,4]) ≡ Array(3, 4) Array.apply(null, [1]) ≡ Array(1) 

E sai cosa fa il costruttore Array quando viene chiamato con un singolo argomento numerico – crea una matrice sparsa di quella lunghezza …

È ansible avere una virgola finale negli array da ECMA 262. La sua presenza non modifica il contenuto dell’array in alcun modo.

Se hai due o più virgole consecutive non consecutive in un array, il loro contenuto viene impostato come indefinito.

Nota: poiché undefined negli array ha un comportamento non standard in IE <9, eviterei di usarlo lì. Utilizzare invece null .

Il fatto che tu abbia risultati sorprendenti quando sparseArr contiene un elemento è perché Array ha due diversi costruttori: se passi più argomenti crea una matrice con quella sequenza, se passi un numero singolo crea una matrice di “numero” di lunghezza pieno di indefinito.

 new Array(1, 2, 3) => [1, 2, 3] new Array(2) => [undefined, undefined]