false >= null
pother_dane
- javascript
0 Cybaer0 romy0 pother_dane
10 Christian Seiler
hallo,
als ich heute auf der konsole (firebug) rumgespielt habe, ist mir folgendes, für mich nicht durchdringbares, phänomen untergekommen:
ich vergleiche null, false und "" und komme zu folgenden, wie ich finde seltsamen ergebnissen:
null < false //--> false
null > false //--> false
null == false //--> false
null != false //--> true
//bis hierhin hätte ich die ausgabe noch richtig vorher gesagt. aber jetzt:
null <= false //--> true
null >= false //--> true
//das selbe mit ""
null < "" //--> false
null > "" //--> false
null == "" //--> false
null != "" //--> true
//und auch hier:
null <= "" //--> true
null >= "" //--> true
vergleiche mit undefined bringen für den durchschnittsverstand (halbwegs) erwartbare ergebnisse.
ich habe dann mal ein wenig in der dokumentation gelesen und versucht zu verstehen warum das so ist. die scheint aber für nichtinformatiker im anfängerstatus bei solchen fragen ein pdf mit einigen siegeln zu sein.
meine vermutung nach der doc-lektüre: es hat etwas damit zu tun, dass null ein objekt, false ein boolean und "" ein string ist. im vorgang des vergleichs werden die typen unterschiedlich "aufgelöst" (nennt man das so?) und eigentlich hat alles sein richtigkeit.
könnten mir das versiertere hier vielleicht erklären/einen hinweis geben?
danke und gruß,
pD
Hi,
könnten mir das versiertere hier vielleicht erklären/einen hinweis geben?
(Auch) JS konvertiert automatisch Datentypen. false ist genauso !true wie null. false==null oder false=="" etc. ist also immer so wahr, wie false<=null.
Wenn Du den Datentyp bei der Bedinung mittesten möchtest, geht das (auch) in JS mit false===null. Das ist dann immer unwahr ...
Gruß, Cybaer
Hi Cybaer,
(Auch) JS konvertiert automatisch Datentypen. false ist genauso !true wie null. false==null oder false=="" etc. ist also immer so wahr, wie false<=null.
Nur interessehalber: der UP hat ja herausgefunden, dass null == false --> false ist und null > false --> false - Aber: null >= false soll true sein, warum der Unterschied, ist glaube ich seine Frage. Wenn alles true wäre, wäre es ja vielleicht wieder logisch.
Wenn Du den Datentyp bei der Bedinung mittesten möchtest, geht das (auch) in JS mit false===null. Das ist dann immer unwahr ...
klar.
ciao
romy
hallo,
(Auch) JS konvertiert automatisch Datentypen. false ist genauso !true wie null. false==null oder false=="" etc. ist also immer so wahr, wie false<=null.
dass js automatisch daten umwandelt ist mir schon klar gewesen. meine verwunderung entsprang dem, wie ich finde, gar nicht so selbstverständlichen umstand, dass null weder kleiner noch größer und auch nicht gleich false ist, aber gleichzeitig kleinergleich/größergleich.
Wenn Du den Datentyp bei der Bedinung mittesten möchtest, geht das (auch) in JS mit false===null. Das ist dann immer unwahr ..
die frage war mehr eine klassische interessefrage als einem programmierproblem gedankt. mit solchen sachen beschäftigt man sich halt wenn man noch lernen muss :)
gruß,
pD
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
hallo,
wow, vielen dank für die ausführliche antwort. im prinzip (wo auch sonst) alles klar. man kann vielleicht sagen: ist mehr eine frage der konvention als eine die sich per menschenverstand so wirklich durchdringen lässt.
eines noch:
Wenn x und y in primitive Datentypen gewandelt keine Strings sind, dann gelten folgende Vergleichsregeln (nach ECMA-262 11.8.5):
- Wandle x in Zahl um
- Wandle y in Zahl um
- Wenn x NaN ist: gib undefined zurück
- Wenn y NaN ist: gib undefined zurück
- Wenn x und y die gleiche Zahl sind, gib false zurück
- Wenn x = +0 und y = -0 ist, gib false zurück
- Wenn x = -0 und y = +0 ist, gib false zurück
- Wenn x = +unendlich ist, gib false zurück
- Wenn y = +unendlich ist, gib true zurück
- Wenn y = -unendlich ist, gib false zurück
- Wenn x = -unendlich ist, gib true zurück
- Führe den mathematischen Vergleich x < y durch und gib das Ergebnis
zurück.
diese liste habe ich mir auch durchgelesen, aber bei so dingen wie -0, +0, -unendlich und +unendlich gingen mir die verständnismöglichkeiten aus. ich nehme mal an, (man verzeih mir meine unfachmännische/falsche ausdrucksweise) das hat was mit den bits ganz am boden der werte zu tun, so in der art? und: was unterscheidet +0/unendlich von -0/unendlich? auf solche fragen selbstständig laiengerechte antworten zu finden ist wirklich sehr schwer... sry!
[1] typeof liefert nicht immer den internen Typ zurück!
gibt es eine andere möglichkeit an die internen typen zu gelangen von der ich noch nichts weiß.
vielen dank nochmal,
gruß
pD
Hallo,
diese liste habe ich mir auch durchgelesen, aber bei so dingen wie -0, +0, -unendlich und +unendlich gingen mir die verständnismöglichkeiten aus. ich nehme mal an, (man verzeih mir meine unfachmännische/falsche ausdrucksweise) das hat was mit den bits ganz am boden der werte zu tun, so in der art? und: was unterscheidet +0/unendlich von -0/unendlich? auf solche fragen selbstständig laiengerechte antworten zu finden ist wirklich sehr schwer... sry!
Das hängt mit Floating-Point-Arithmetik zusammen. Eine Floating-Point-Zahl im Computer setzt sich aus 3 Dingen zusammen:
Mathematisch ist eine Floating-Point-Zahl so zu lesen:
(-1)^Vorzeichen * Mantisse * 2^Exponent
Wenn man von Details wie der genauen Kodierung mal absieht ergeben sich +/-0, +/-unendlich und NaN aus folgender Überlegung:
+/-0 ist einfach eine Notwendigkeit auf Grund der Tatsache, dass es ein Vorzeichenbit gibt. Im Gegensatz zu Ganzzahlen, die fast immer im Zweierkomplement dargestellt werden, kann man hier kein Zweierkomplement nutzen und muss daher ein Extra-Vorzeichenbit haben. Da Zahl ohne Bit gesetzt = - Zahl mit Bit gesetzt sein sollte (wenn man nicht komplett am Rad drehen will ;-)), gibt es eben zu +0 ein -0 als Äquivalent. Die Vergleichsregeln von eigentlich allen Programmiersprachen sagen jedoch, dass +0 == -0 ist, siehe auch die Regeln für JS.
NaN ergibt soch aus unbestimmten Ausdrücken: 0/0 z.B. ist NaN, genauso wie die Versuchte Umwandlung vom String "abc" in ein Float. NaN steht für Not a Number und wird durch ein bestimmtes festgelegtes Bitmuster kodiert.
+/-unendlich zeigen Überläufe an. Es gibt auch bei Floats eine größte darstellbare Zahl und wenn Du eine Operation durchführst, die über diese Zahl hinausgeht, dann wird durch +unendlich der Überlauf gekennzeichnet, den kann man damit auch abfangen.
NaN, +/-unendlich und +/-0 spielen auch noch auf verschiedene Arten zusammen, was die Nützlichkeit nochmal erhöht, worauf ich hier aber nicht genauer eingehen will.
Wenn Dich näheres zu FP-Arithemtik interessiert: http://docs.sun.com/source/806-3568/ncg_goldberg.html (Achtung: Langes, teilweise etwas schwer zu verdauendes Dokument, aber sehr informativ)
[1] typeof liefert nicht immer den internen Typ zurück!
gibt es eine andere möglichkeit an die internen typen zu gelangen von der ich noch nichts weiß.
Naja, typeof ist eigentlich schonmal ein sehr guter Start, Du musst lediglich noch einige Spezialfälle abarbeiten. Wenn type == "object" ist, dann kann das vom Typ her auch null sein, d.h. Du musst extra noch auf "null" prüfen. Und es gibt noch ein paar andere Fälle diesbezüglich, es gab vor einiger Zeit mal im Archiv eine Diskussion zum Thema, Thema damals war, warum typeof für "function"-Objekte eine Ausnahme macht, für "array"-Objekte aber nicht.
Viele Grüße,
Christian