Frage

Ich habe mit JavaScript-Arrays zu spielen und ich habe laufen in, was ich fühle, sind einige Ungereimtheiten, ich hoffe jemand sie mir erklären kann.

Fangen wir mit dieser beginnen:


var myArray = [1, 2, 3, 4, 5];
document.write("Length: " + myArray.length + "<br />");
for( var i in myArray){
   document.write( "myArray[" + i + "] = " + myArray[i] + "<br />");
}
document.write(myArray.join(", ") + "<br /><br />");
Length: 5
myArray[0] = 1
myArray[1] = 2
myArray[2] = 3
myArray[3] = 4
myArray[4] = 5
1, 2, 3, 4, 5

Es gibt nichts Besonderes an diesem Code, aber ich verstehe, dass ein JavaScript-Array ein Objekt ist, so properities zum Array hinzufügen können, die Art, wie diese properities zu einem Array hinzugefügt werden, scheint mir inkonsistent.

Bevor wir fortfahren, lassen Sie mich bemerken, wie String-Werte sind Zahlenwerte in Javascript umgewandelt werden.

  • Nicht leere string -> Numerisch Wert von String oder NaN

  • Leere String -> 0

So, da ein Javascript-Array ist ein Objekt folgenden ist legal:


myArray["someThing"] = "someThing";
myArray[""] = "Empty String";
myArray["4"] = "four";

for( var i in myArray){ document.write( "myArray[" + i + "] = " + myArray[i] + "<br />"); } document.write(myArray.join(", ") + "<br /><br />");

Length: 5
myArray[0] = 1
myArray[1] = 2
myArray[2] = 3
myArray[3] = 4
myArray[4] = four
myArray[someThing] = someThing
myArray[] = Empty String
1, 2, 3, 4, four

Der Ausgang ist unerwartet.

Die nicht leere Zeichenkette „4“ in seinen numerischen Wert umgewandelt wird, wenn die Eigenschaft myArray Einstellung [ „4“], das scheint recht. Doch die leere Zeichenkette „“ in seinen numerischen Wert nicht umgewandelt wird, 0 ist, wird es als eine leere Zeichenfolge behandelt. Auch die nicht leere Zeichenkette „etwas“ ist nicht auf seinen numerischen Wert umgewandelt, NaN, wird als String behandelt. Also, was ist es? ist die Anweisung innerhalb arr [] in Zusammenhang numerisch oder String?

Auch, warum sind die beiden, nicht numerisch, properities von myArray nicht in myArray.length und myArray.join ( "") enthalten?

War es hilfreich?

Lösung

Die Tasten eines JavaScript-Array sind eigentlich Saiten. Details und einer Implementierung eines Kartentyp für beliebige Tasten, überprüfen diese Antwort .


Um zu klären, und fügen Sie, was Jason geschrieben: JavaScript-Arrays Objekte sind. Objekte haben Eigenschaften. Ein Eigenschaftsname ist ein String-Wert. Daher Array-Indizes werden auch in Strings umgewandelt, bevor etwas mehr passieren kann. Ein Eigenschaftsname P wird als ein Array-Index behandelt werden (dh der speziellen Array-Magie wird aufgerufen), wenn gilt (ECMA-262, 15,4):

  

ToString (ToUint32 (P)) gleich P und ToUint32 (P) nicht gleich 2 ^ 32-1

Der numerische Indizes wird in Strings konvertiert werden (und nicht umgekehrt) kann leicht überprüft werden:

var array = [];
array[1] = 'foo';
array['1'] = 'bar';
array['+1'] = 'baz';
document.writeln(array[1]); // outputs bar

Auch seine schlechte Praxis eines Arrays Eintrag mit einer for..in Schleife iterieren - Sie unerwartete Ergebnisse erhalten könnten, wenn jemand mit einigen Prototypen messed (und es ist nicht wirklich schnell, entweder). Verwenden Sie den Standard-for(var i= 0; i < array.length; ++i) statt.

Andere Tipps

(edit: die folgende ist nicht ganz richtig)

Die Tasten eines JavaScript Object sind eigentlich Saiten. A Javascript Array von selbst haben numerischen Indizes. Wenn Sie etwas mit einem Index speichern, die als nicht-negative ganze Zahl interpretiert werden kann, wird es versuchen, dies zu tun. Wenn Sie etwas mit einem Index zu speichern, die nicht eine nicht negative ganze Zahl ist (zB es ist alphanumerische, negativ oder eine Gleitkommazahl mit einem fraktionierten Stück), wird es auf dem Array-Indexspeicher fehlschlagen, und standardmäßig auf die Objekt (das ist Basisklasse Array) zu speichern, die dann das Argument von Stringindex in einen String und speichert wandelt - aber diese gespeicherten Eigenschaften werden durch die Array-Klasse und sind daher nicht sichtbar auf seine Methoden / Eigenschaften gesehen ( Länge, verbindet, in Scheiben schneiden, Spleiß, push, pop, etc).

edit: die oben ist nicht ganz richtig (wie Christopher foo / bar / baz Beispiel zeigt). Die tatsächliche Speicherindizes nach dem ECMAscript spec ist, in Tatsache, Strings, aber wenn sie gültige Array-Indizes (natürliche Zahlen), dann das [[Put]] Methode des Array-Objekts, das speziell ist, macht diese besondere Werte sichtbar für den „Array-ish“ Methoden des Array.

Dies ist eine Antwort auf Philos Post . Seine Benchmark ist fehlerhaft, da er verschiedene Eigenschaftsnamen für die Objekt-Version verwendet. Er sollte auch i verwendet hat und nicht x

Wenn es richtig gemacht, wie dies zum Beispiel:

var start, end, count = 1000000;

var obj = {},
    array = [];

start = new Date;
for(var i = count; i--; )
    array[i] = i;
end = new Date;
document.writeln(Number(end) - Number(start));

start = new Date;
for(var i = count; i--; )
    obj[i] = i;
end = new Date;
document.writeln(Number(end) - Number(start));

Sie werden sehen, dass die Zeiten, ganz in der Nähe sein. In FF3.0.5 ist die Array-Version auch konsequent langsamer (in Opera, es ist umgekehrt).

Arrays, wie alles andere in JavaScript, sind Objekte. Objekte wurden gesegnet mit der Punktnotation die Belastung für die Entwickler zu erleichtern. Mit Ihrem Beispiel

myArray["someThing"] = "someThing";

ist das gleiche wie das Schreiben

myArray.someThing = "someThing";

In diesem Fall fügen Sie ein Objekt auf das Objekt, anstatt sie in das Array hinzuzufügen. Das gleiche gilt mit dem leeren String, obwohl Sie nicht die Punktnotation für einen leeren String ... seltsam verwenden können, nicht wahr?

In dem Fall von „4“ ist, kann es in eine ganze Zahl umgewandelt werden, und daher als ein Index in das Array verwendet wird.

Ich bin nicht einverstanden mit Christoph, wenn er sagt "Array-Indizes umgewandelt werden in Strings".

Erstens glaube ich, es Implementierung abhängig ist ... Ich nehme an (gut) Implementierer Array-Zugriff zu optimieren, gibt es einige intelligenten Möglichkeiten, es zu tun.

Eigentlich habe ich einen kleinen Test, und obwohl es so gut, wie die meist Mikro-Benchmarks ist, es ist interessant, (dh nicht super-zuverlässig.):

result = ""
var x;

var trueArray = []
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "i" + i; // To do the same operations
  trueArray[i] = 1;
}
var endTime = new Date();
result += "With array: " + (endTime - startTime) + "\n";

var sArray = []
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "" + i;
  sArray[x] = 1;
}
var endTime = new Date();
result += "With s array: " + (endTime - startTime) + "\n";

var objArray = {}
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "i" + i;
  objArray[x] = 1;
}
var endTime = new Date();
result += "With object(i): " + (endTime - startTime) + "\n";

var sobjArray = {}
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "" + i;
  sobjArray[x] = 1;
}
var endTime = new Date();
result += "With s object: " + (endTime - startTime) + "\n";

var iobjArray = {}
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "" + i;
  iobjArray[i] = 1;
}
var endTime = new Date();
result += "With i object: " + (endTime - startTime) + "\n";


// Then display result

Auf IE6, erhalte ich: Mit Array: 1453 Mit Objekt: 3547
Auf FF 3.0, erhalte ich: Mit Array: 83 Mit Objekt: 226
Auf Safari 3.1, erhalte ich: Mit Array: 140 Mit Objekt: 313
Auf Opera 9.26 aus irgendeinem Grund bekomme ich das Ergebnis nicht, aber wenn ich auf die Zehntel Anzahl der Schleifen zu verringern, erhalte ich: Mit Array: 47 Mit Objekt: 516
Eigentlich ließ ich Opera laufen, während ich dies schreibe, und bekam schließlich das Ergebnis: Mit Array: 281 Mit Objekt: 166.063 ...

So Arrays optimiert! Welches ist das Glück ...
Christoph Demonstration hat mich nicht beeindruckt. Meine Schlussfolgerung wäre, dass Zeichenketten, die als Zahlen interpretiert werden können, werden als solche behandelt, die mit der genannten Formel mitgehen ...

So ist meine Interpretation der Ergebnisse ist, dass das Array wie eine schnelle Array verhält sich mit numerischem Indizes, wenn sie mit diesem Futtermittel (vielleicht mit einem Verhalten von assoziativen Arrays auf spärlichen Werten, dh. Ein paar isolierten große Indizes), sondern als Objekt es hat immer noch die normale Handhabung von Eigenschaften. Aber diese Eigenschaften sind nicht im Array-Teil behandelt, damit das Ergebnis Sie wurde mit join ().

[EDIT] Ich habe einige Schleifen hinzugefügt, nachdem Christoph Idee.
Auf FF3, erhalte ich: Mit Array: 92 Mit s-Array: 93 Mit Objekt (i): 243 Mit s Objekt: 194 Mit i-Objekt: 125 (perfs variiert zwischen den Läufen, sind aber etwa konsistent).

Ich bin nicht super-überzeugt diese integer -> string -> integer Round-Trip, nicht einmal, dass die ECMA-Anfragen dieser Sequenz. Die Art, wie ich las es ist. Ist die Eigenschaft eine Zeichenfolge ist und kann als ganze Zahl interpretiert werden, dann wird sie als solche behandelt

Natürlich ist der einzig sichere Weg wäre zu wissen, bei einer Implementierung aussehen ...

ich mit Interesse fest, die schlicht Objekte eine Integer-Eigenschaft oder eine Eigenschaft erhalten, die auf eine ganze Zahl umgewandelt werden kann irgendwie optimiert sind. Vielleicht, weil viele JS-Programmierer verwendete Ebene Objekte wie Arrays, so beurteilt Implementierer interessant, diesen Fall zu optimieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top