Hallo!
ich habe dann mal ein wenig in der dokumentation gelesen und versucht zu verstehen warum das so ist.
Der Hintergrund ist eigentlich ziemlich einfach:
null ist vom Typ null [1] und evaluiert nach:
false im Boolean-Kontext
0 im Zahlen-Kontext
"null" im String-Kontext
undefined ist vom Typ undefined und evaluiert nach:
false im Boolean-Kontext
NaN im Zahlen-Kontext
"undefined" im String-Kontext
Die Frage bleibt jetzt, wann implizite Typumwandlungen bei Vergleichen stattfinden. Und die Regeln sind wie folgt für x == y bzw. x != y, falls die Typen nicht gleich sind:
[Nummerierung an Hand ovn ECMA-262 11.9.3]
14. x ist undefined, y ist null: true
15. x ist null, y ist undefined: true
16. x ist Zahl, y ist String: Wandle y in eine Zahl um und vergleiche dann
17. x ist String, y ist Zahl: Wandle x in eine Zahl um und vergleiche dann
18. x ist Boolean, y ist etwas anderes: Wandle x in eine Zahl um und
vergleiche dann
19. y ist Boolean, x ist etwas anderes: Wandle y in eine Zahl um und
vergleiche dann
20. x ist String oder Zahl und y ist Objekt: Wandle y in einen primitiven
Datentypen um und vergleiche
dann.
21. y ist String oder Zahl und x ist Objekt: Wandle x in einen primitiven
Datentypen um und vergleiche
dann.
22. Wenn keines der obigen zutrifft: false
Das heißt, für null == false:
Fällt in Fall 19, also wird false in eine Zahl umgewandelt (gibt 0) und dann verglichen: null == 0. Typ null und Typ Zahl tauchen aber nicht in der obigen Liste auf, also trifft 22 zu und das Ergebnis ist false.
Für den Fall undefined == false:
Fällt in den Fall 19, also wird false in eine Zahl umgewandelt (gibt 0) und dann verglichen: undefined == 0. Typ undefined und Typ Zahl tauchen aber nicht in der obigen Liste auf, also trifft 22 zu und das Ergebnis ist false.
Betrachten wir nun die Regeln für die Vergleiche x < y, x <= y, x > y und x >= y:
Wenn x und y in primitive Datentypen gewandelt keine Strings sind, dann gelten folgende Vergleichsregeln (nach ECMA-262 11.8.5):
4. Wandle x in Zahl um
5. Wandle y in Zahl um
6. Wenn x NaN ist: gib undefined zurück
7. Wenn y NaN ist: gib undefined zurück
8. Wenn x und y die gleiche Zahl sind, gib false zurück
9. Wenn x = +0 und y = -0 ist, gib false zurück
10. Wenn x = -0 und y = +0 ist, gib false zurück
11. Wenn x = +unendlich ist, gib false zurück
12. Wenn y = +unendlich ist, gib true zurück
13. Wenn y = -unendlich ist, gib false zurück
14. Wenn x = -unendlich ist, gib true zurück
15. Führe den mathematischen Vergleich x < y durch und gib das Ergebnis
zurück.
Das wird dann in die Operatoren "<" und ">=" so umgesetzt:
| verwend. Vergleichsoperator
Ergebnis des Vergleichs | < | >=
------------------------+-------+-------
true | true | false
false | false | true
undefined | false | false
(Bei ">" und "<=" werden nur die beiden Operatoren vertauscht.)
Betrachten wir nun den Fall null < false:
Schritt 4 wandelt null in eine Zahl um, ergibt +0. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Beide sind mathematisch gleich, Fall 8, also ergibt das ganze false, false ergibt in der Lookup-Tabelle für < ein false.
Betrachten wir nun den Fall undefined < false:
Schritt 4 wandelt undefined in eine Zahl um, ergibt NaN. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Fall 6 tritt ein, ergebnis ist undefined. In der Lookuptabelle ergibt sich nun für "<" das Resultat false.
Also ist null < false == false und undefined < false == false.
Betrachten wir nun den Fall null <= false - der ist identisch mit dem Fall false >= null:
Schritt 4 wandelt null in eine Zahl um, ergibt +0. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Beide sind mathematisch gleich, Fall 8, also ergibt das ganze false, false ergibt in der Lookup-Tabelle für >= ein true.
Betrachten wir nun den Fall undefined <= false - der ist identisch mit dem Fall false >= undefined:
Schritt 4 wandelt undefined in eine Zahl um, ergibt NaN. Schritt 5 wandelt false in eine Zahl um, ergibt +0. Fall 6 tritt ein, ergebnis ist undefined. In der Lookuptabelle ergibt sich nun für ">=" das Resultat false.
Also ist false >= null == true und undefined >= null == false.
Das gleiche Spiel ist auch bei "" der Fall, da "" in eine Zahl gewandelt eben auch 0 ergibt (damit < und > andere Semantiken bei Stringvergleichen haben, müssen beides Strings sein).
Ich hoffe, ich konnte damit das ganze etwas verdeutlichen.
[1] typeof liefert nicht immer den internen Typ zurück!
Viele Grüße,
Christian