2013-04-11 20 views
12

Sto scrivendo un interprete JavaScript per dispositivi embedded con risorse limitate (http://www.espruino.com) e ogni volta che penso di aver implementato correttamente un po 'di codice JavaScript mi ​​rendo conto di avere torto.In che modo JavaScript [] funziona davvero?

La mia domanda ora è di circa []. Come implementeresti correttamente uno dei bit più basilari di JavaScript?

Ho esaminato le specifiche di JavaScript e forse non ho trovato il bit giusto, ma non riesco a trovare una risposta utile.

In precedenza avevo ipotizzato che fossero effettivamente presenti due "mappe", una per i numeri interi e una per le stringhe. E la lunghezza dell'array era il valore del numero intero più alto più uno. Tuttavia, questo sembra sbagliato, secondo JSConsole su bicromato di potassio:

var a = []; 
a[5] = 42; 
a["5"]; // 42 
a.length; // 6 

ma anche:

var a = []; 
a["5"] = 42; 
a[5]; // 42 
a.length; // 6 

Quindi ... grande - tutto viene convertito in una stringa, e il più alto valore di stringa che rappresenta un numero intero è usato (più uno) per ottenere la lunghezza? Sbagliato.

var a = []; 
a["05"] = 42; 
a.length; // 0 

"05" è un intero valido - anche in ottale. Quindi perché non influisce sulla lunghezza?

Devi convertire la stringa in un numero intero e quindi verificare che, quando viene convertita in una stringa, corrisponda?

Qualcuno ha un riferimento all'algoritmo esatto utilizzato per archiviare e ottenere elementi in un array o in un oggetto? Sembra che dovrebbe essere molto semplice, ma sembra che in realtà non lo sia!

+6

[Lo standard] (http://www.ecma-international.org/ecma-262/5.1/#sec-15.4) dice: "* Un nome di proprietà' P' (sotto forma di 'String' value) è un indice di array se e solo se 'ToString (ToUint32 (P))' è uguale a 'P' e' ToUint32 (P) 'non è uguale a' 2 ** 32-1'. * ". – DCoder

+6

Se stai scrivendo un interprete, le ipotesi non dovrebbero essere usate. Dovresti leggere le specifiche. –

+0

Perché non usi implementazioni JS esistenti, potenti e conformi allo standard, come V8? Quello che ho letto su http://www.espruino.com/Performance suonava orribile: -/ – Bergi

risposta

4

Poichè spec detto, ed è stato rilevato da altri:

"A nome della proprietà P (sotto forma di un valore stringa) è un indice di matrice se e solo se ToString (ToUint32 (P)) è uguale a P e ToUint32 (P) non è uguale a 2^32-1. "

Quel spiegare il motivo per cui nel vostro scenario "5" è considerato un indice di matrice e "05" non è:

console.log("5" === String("5" >>> 0)); 
// true, "5" is equal to "5", so it's an index 

console.log("05" === String("05" >>> 0)); 
// false, "05" is not equal to "5", so it's not an index 

Nota: il Zero-fill right shift è la via più breve in JS di avere un sostituto di ToUint32, spostando un numero da zero.

+0

Grazie - questo spiega anche il problema con la lunghezza dell'array, che altre risposte in realtà non hanno risolto. Grazie per il collegamento alle specifiche e anche DCoder –

3

Le matrici sono solo oggetti. Ciò significa che possono avere proprietà aggiuntive che non sono considerate elementi dell'array.

Se l'argomento parentesi quadra è un numero intero, viene utilizzato per eseguire un'assegnazione all'array. Altrimenti, lo tratta come una stringa e la memorizza come una proprietà sull'oggetto array.

Edit in base a commento di delnan e commentare di DCoder, questo è il modo Javascript determina se si tratta di un indice appropriato per un array (contro solo una proprietà): http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

+0

L'ultima parte non è particolarmente utile a meno che non si definisca * quale sia esattamente * "un numero intero" e cosa no.Ad esempio, "05" è un numero intero e perché (non)? – delnan

4

Vedi MDN

È anche possibile citare gli indici di array JavaScript (ad esempio, anni ["2"] invece di anni [2]), anche se non è necessario. Il 2 in anni [2] viene infine forzato in una stringa dal motore JavaScript , tramite una conversione implicita di toString. E 'per questo motivo che "2" e "02" potrebbe riferirsi a due slot differenti sulla gli anni oggetto e il seguente esempio registra vero:

console.log(years["2"] != years["02"]); 

Quindi, con a["5"] si accede la matrice, mentre a["05"] imposta una proprietà sull'oggetto matrice.

1

Gli array sono anche oggetti.

In questo modo

a["05"] = 5; 

Si sta facendo la stessa cosa:

a.05 = 5; 

Tuttavia, quanto sopra si tradurrà in un errore di sintassi, come una proprietà specificato dopo un punto non può inizia con un numero.

Quindi, se si esegue questa operazione:

a = []; 
a["05"] = 5; 

avete ancora un vuoto serie, ma la proprietà di a denominata 05 ha il valore 5.

Il numero xis an array index se e solo se ToString(ToUint32(x)) è uguale a x (quindi in caso di "05" tale condizione non è soddisfatta).

Problemi correlati