Javascript ist Toll!

28. Oktober 2009 - 13:30

Vergleiche mit Javascript

Vergleiche mit Javascript und ihre Merkwürdigkeiten.
Eigentlich sollte man meinen, Vergleiche wären eine klare Sache. Entweder es ist etwas identisch oder nicht. Fertig!

So einfach ist es aber leider nicht. Da in Javascript eine automatische Typkonvertierung existiert, die zumindest in einen Sonderfall zu einem merkwürdigen Ergebnis führt. Entdeckt habe ich dieses Verhalten gestern in einem längeren Thread im selfhtml Forum. Dort war die Frage aufgetaucht, warum ("0" && "1") 1 ergibt (test). Im weiteren Verlauf stellten wir fest, dass die Vergleiche sehr seltsame Ergebnisse hatten. Z.b. der folgende Code:

var str = '0';
alert( 
'str==true => ' + (str == true)
+ 'n' 
+ '!str==true => ' + (!str == true)
);
klicken!

Der Wert ist nicht wahr und er ist aber auch nicht unwahr. Wie kann das sein?

Typkonvertierung

Da Javascript keine Datentypen bei der Deklaration kennt, wie in manchen anderen Sprachen, muss bei Operationen immer eine Konvertierung erfolgen, wenn auf den Seiten des Operators verschiedene Datentypen benutzt werden.

Die Konvertierung erfolgt dann grundsätzlich zu sogenannten primitiven Werte. Das sind die einfachsten Werte die Javascript darstellen kann: Undefined, Null, Boolean, Number, String.

Bei allen Operationen in JS gibt es exakte Ablaufpläne wie Berechnungen durchgeführt werden, wenn unterschiedliche primitive Typen verwendet werden. Diese werden genau beschrieben in der ECMA-262 Spezifikation.

ECMA-262

Der Ablauf von Vergleichen wird im Abschnitt 11.9.3 The Abstract Equality Comparison Algorithm beschrieben. Er umfasst 22 Schritte und einige Anmerkungen. Für die Fragestellung oder das Problem, sind die Punkte 18+19 entscheidend. Hier der Ausschnitt aus der Spezifikation:

The comparison x == y, where x and y are values, produces true or false. Such a comparison is
performed as follows:
1. If Type(x) is different from Type(y), go to step 14.
[...]
14. If x is null and y is undefined, return true.
15. If x is undefined and y is null, return true.
16.If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
17.If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
18. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
19. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
[...]

Da bei dem Vergleich auf false geprüft wird, also einem Booleschen Wert, muss die Regeln 18 oder 19 auf den Code angewendet werden. Und dort steht nicht, wie ich es eigentlich erwartet hätte, dass der String zu einem Booleschen Typ umgewandelt wird, sondern zu einer Zahl(!). Das das tatsächlich so ist, lässt sich prüfen indem die Umwandlung explizit mit Number() durchgeführt wird:

var str = '0';
alert( 
'str==true => ' + (str == Number(true))
+ 'n' 
+ '!str==true => ' + (!str == Number(true))
);

Damit wird auch klar, warum der Vergleich immer false ist. Da Number(true) 1 ergibt, ist sowohl '0' als auch !'0' immer falsch. '0' wird zu einer Zahl umgewandelt (Regel 16/17) und !'0' wird zu false, was dann wiederrum zu einer '0' wird.

Das bedeutet, wenn eine Zeichenkette verglichen werden soll, muss man sich im klaren sein, dass false immer zu 0 und true immer zu 1 wird und das auch Zeichenkette in eine Zahl umgewandelt wird.

var str = '0';
alert( str  == 0 ); // entspricht == false
alert( str  == 1 ); // entspricht == true

Gleich und Gleicher (Nachtrag: 2.11.2009)

In dem zusammenhang fiel mir auf, dass manche JS Koryphäen (z.b. Douglas Crockford) bei Vergleichen den expliziten Vergleichsoperator (===) empfehlen. Unter anderen auch wegen dieser Problematik. Wenn man sich aber die Problematik genau anschaut, ist es keine mehr, wenn explizite Vergleiche auf einen wahren oder falschen Wert vermieden werden.

Die Schreibweise if(wert) ist entweder wahr oder falsch. Der Vergleich hingegen if(wert == true) bzw if(wert == false) unterliegt den obigen Gesetzmäßigkeiten.
In aller Regel soll ein solcher Test aber genau das ermitteln, was der kurze Ausdruck darstellt: Wenn wert eine Zeichenkette ist, soll der Ausdruck wahr sein wenn die Zeichenkette eine Länge größer Null hat. Ein unwahre Zahl ist Null oder NaN und ein wahres Objekt ist ungleich null.

Deshalb empfehle ich bei Überprüfungen auf unwahre Werte, also Null (Zahl), Leerstring, false oder Null (Objekt), immer die Kurzfrom zu verwenden.

weiterführender Link

Hier noch ein englischer Artikel der das ganze noch etwas detaillierter erklärt. http://www.united-coders.com/matthias-reuter/all-about-types-part-2

Danke an LanX! für die Frage und DonP für die erkenntnisreiche Diskussion

ähnliche Artikel

  • 27. Oktober 2012 -- Tween Beispiele (0)

    Das Tween Objekt Ich vertiefe hier noch einmal die...

  • 22. Juni 2012 -- Tween(2) (0)

    Die Technik um mit Javascript eine Bewegung zu animieren...

  • 15. Juni 2012 -- Wordpress und Javascript (2)

    In der letzten Zeit durfte ich mich etwas intensiver...

Comments (0)
917 mal gelesen.

Noch keine Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Powered by WordPress Stop Spam Harvesters, Join Project Honey Pot
rats-wonderful
rats-wonderful
rats-wonderful
rats-wonderful