Stranezza di “nuovo array (n)” e “Array.prototype.map”

Ho osservato questo in Firefox-3.5.7 / Firebug-1.5.3 e Firefox-3.6.16 / Firebug-1.6.2

Quando accendo Firebug:

>>> x = new Array(3) [undefined, undefined, undefined] >>> y = [undefined, undefined, undefined] [undefined, undefined, undefined] >>> x.constructor == y.constructor true >>> x.map(function(){ return 0; }) [undefined, undefined, undefined] >>> y.map(function(){ return 0; }) [0, 0, 0] 

Cosa sta succedendo qui? È un bug o sto fraintendendo come usare il new Array(3) ?

Sembra che il primo esempio

 x = new Array(3); 

Crea una matrice con puntatori non definiti.

E il secondo crea un array con puntatori a 3 oggetti non definiti, in questo caso i puntatori su se stessi NON sono indefiniti, solo gli oggetti a cui puntano.

 y = [undefined, undefined, undefined] // The following is not equivalent to the above, it's the same as new Array(3) y = [,,,]; 

Poiché la mappa viene eseguita nel contesto degli oggetti nell’array, credo che la prima mappa non riesca a eseguire la funzione mentre la seconda riesce a funzionare.

Ho avuto un compito che conoscevo solo per la lunghezza dell’array e che dovevo trasformare gli oggetti. Volevo fare qualcosa del genere:

 let arr = new Array(10).map((val,idx) => idx); 

Per creare rapidamente un array come questo:

 [0,1,2,3,4,5,6,7,8,9] 

Ma non ha funzionato perché: vedi la risposta di Jonathan Lonowski qualche risposta in alto.

La soluzione potrebbe essere quella di riempire gli elementi dell’array con qualsiasi valore (anche con undefined) usando Array.prototype.fill ()

 let arr = new Array(10).fill(undefined).map((val,idx) => idx); 
 console.log(new Array(10).fill(undefined).map((val, idx) => idx)); 

Con ES6, puoi fare [...Array(10)].map((a, b) => a) , veloce e facile!

Dalla pagina MDC per la map :

[…] il callback è invocato solo per gli indici dell’array che hanno assegnato un valore; […]

[undefined] applica effettivamente il setter sull’indice (i) in modo tale che la map itererà, mentre il new Array(1) inizializza semplicemente l’indice (i) con un valore predefinito undefined quindi la map salta.

Credo che questo sia lo stesso per tutti i metodi di iterazione .

Gli array sono diversi. La differenza è che la new Array(3) crea una matrice con una lunghezza di tre ma nessuna proprietà, mentre [undefined, undefined, undefined] crea una matrice con una lunghezza di tre e tre proprietà chiamate “0”, “1” e ” 2 “, ciascuno con un valore undefined . Puoi vedere la differenza usando l’operatore in:

 "0" in new Array(3); // false "0" in [undefined, undefined, undefined]; // true 

Questo deriva dal fatto un po ‘confuso che se si tenta di ottenere il valore di una proprietà inesistente di qualsiasi object nativo in JavaScript, esso restituisce un valore undefined (piuttosto che generare un errore, come accade quando si tenta di fare riferimento a un inesistente variabile), che è lo stesso di quello che si ottiene se la proprietà è stata precedentemente impostata esplicitamente su undefined .

Soluzione ES6:

 [...Array(10)] 

Non funziona su typescript (2.3), però

Penso che il modo migliore per spiegarlo sia osservare il modo in cui Chrome lo gestisce.

 >>> x = new Array(3) [] >>> x.length 3 

Quindi ciò che sta realmente accadendo è che la nuova Array () restituisce un array vuoto che ha una lunghezza di 3, ma nessun valore. Pertanto, quando si esegue x.map su un array tecnicamente vuoto, non c’è nulla da impostare.

Firefox “riempie” quegli spazi vuoti con un undefined anche se non ha valori.

Non penso che questo sia esplicitamente un bug, solo un modo scadente di rappresentare ciò che sta accadendo. Suppongo che Chrome sia “più corretto” perché mostra che in realtà non c’è nulla nell’array.

Mi sono imbattuto in questo. Sarebbe sicuramente comodo poter usare Array(n).map .

Array(3) produce circa {length: 3}

[undefined, undefined, undefined] crea le proprietà numerate:
{0: undefined, 1: undefined, 2: undefined, length: 3} .

L’implementazione map () agisce solo su proprietà definite.

Nella specifica della 6a edizione di ECMAScript.

new Array(3) definisce solo la length proprietà e non definisce le proprietà dell’indice come {length: 3} . vedere https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len passaggio 9.

[undefined, undefined, undefined] definirà le proprietà dell’indice e la proprietà della lunghezza come {0: undefined, 1: undefined, 2: undefined, length: 3} . vedere https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList Passaggio 5.

i metodi map , every , some , forEach , slice , reduce , reduceRight , filter of Array controlleranno la proprietà index mediante il metodo interno HasProperty , quindi la new Array(3).map(v => 1) non invocherà il callback.

per maggiori dettagli, consultare https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

Come risolvere?

 let a = new Array(3); a.join('.').split('.').map(v => 1); let a = new Array(3); a.fill(1); let a = new Array(3); a.fill(undefined).map(v => 1); let a = new Array(3); [...a].map(v => 1); 

Non un bug Ecco come viene definito il costruttore Array per funzionare.

Da MDC:

Quando si specifica un singolo parametro numerico con il costruttore Array, si specifica la lunghezza iniziale dell’array. Il codice seguente crea una matrice di cinque elementi:

 var billingMethod = new Array(5); 

Il comportamento del costruttore Array dipende dal fatto che il singolo parametro sia un numero.

Il metodo .map() include solo negli elementi di iterazione dell’array che hanno assegnato esplicitamente valori assegnati. Anche un’assegnazione esplicita di undefined farà sì che un valore sia considerato idoneo per l’inclusione nell’iterazione. Sembra strano, ma è essenzialmente la differenza tra una proprietà undefined esplicita su un object e una proprietà mancante:

 var x = { }, y = { z: undefined }; if (xz === yz) // true 

L’object x non ha una proprietà chiamata “z”, e l’object y fa. Tuttavia, in entrambi i casi sembra che il “valore” della proprietà undefined sia undefined . In una matrice, la situazione è simile: il valore della length esegue implicitamente un’assegnazione di valore a tutti gli elementi da zero alla length - 1 . Pertanto, la funzione .map() non farà nulla (non richiamerà la callback) quando viene chiamata su una matrice di nuova costruzione con il costruttore Array e un argomento numerico.

Se stai facendo questo per riempire facilmente un array con valori, non puoi usare fill per ragioni di supporto del browser e davvero non vuoi fare un ciclo for, puoi anche fare x = new Array(3).join(".").split(".").map(... che ti darà un array di stringhe vuote.

Abbastanza brutto devo dire, ma almeno il problema e l’intenzione sono comunicati abbastanza chiaramente.

In Chrome, se faccio il new Array(3) ottengo [] , quindi la mia ipotesi è che si sia imbattuto in un bug del browser.