JS Typprobleme
LanX!
- javascript
meine JS Kenntnisse sind ein bisschen eingerostet, aber folgendes Typingproblem stell mich vor ein Rätsel
<html>
<body>
<script>
// for ( A in [false,true] ) {
for ( A in [0,1] ) {
for ( B in [0,1]) {
document.writeln("isNaN(A) "+isNaN(A));
document.writeln("isNaN(B) "+isNaN(B));
/*
A=Number(A);
B=Number(B);
*/
document.writeln("<br>"+A+"&&"+B+" -> "+ (A && B )+"<br>");
}
}
document.writeln("<hr> ");
for ( A=0;A<=1;A++ ) {
for ( B=0;B<=1;B++ ) {
document.writeln("<br>"+A+"&&"+B+" -> "+ (A && B )+"<br>");
}
}
</script>
</body>
</html>
ergibt sowohl in FF als auch in Opera
isNaN(A) false isNaN(B) false
0&&0 -> 0
isNaN(A) false isNaN(B) false
0&&1 -> 1 <--- HÄ ???
isNaN(A) false isNaN(B) false
1&&0 -> 0
isNaN(A) false isNaN(B) false
1&&1 -> 1
-----------------
0&&0 -> 0
0&&1 -> 0
1&&0 -> 0
1&&1 -> 1
man beachte dass der auskommentierte Code zum expliziten nummifizieren das Problem behebt....ob A und B aus [true,false} oder [0,1] ändert nix.
OK ich hatte die Vermutung das A und B irgendwie Objektreferenzen sind, die komisch numifiziert werden... aber wieso liefert isNaN dann immer false???
Bitte öffnet mir die Augen ...
Gruß
Rolf
OK
mein Hirn arbeitet langsam wieder, JS ist kein Perl, "in" liefert mir nicht den value sondern den key im Array-Objekt.
Trotzdem verstehe ich noch nicht warum A=0 in der ersten Zeile false und in der zwoten true ist...
Cheers
Rolf
mein Hirn arbeitet langsam wieder, JS ist kein Perl, "in" liefert mir nicht den value sondern den key im Array-Objekt.
Und folglich eine Zeichenkette.
Trotzdem verstehe ich noch nicht warum A=0 in der ersten Zeile false und in der zwoten true ist...
Weil true && wert => wert und alert(!!"0") => true
Struppi.
Hi Struppi,
short circuit gibts ja auch perl
----https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Logical_Operators
Logical AND (&&)
expr1 && expr2
Returns expr1 if it can be converted
to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.
----
aber jetzt kann ich noch mehr schätzen, dass in perl der string "0" false ist!
perl -e 'print !!("0"&&"1")'
ist false
javascript:alert(!!("0"&&"1"))
ist true
Faszinierend!
Danke
Rolf
aber jetzt kann ich noch mehr schätzen, dass in perl der string "0" false ist!
Darüber kann man sich wahrscheinlich streiten, da Perl hier eine doppelte Typkonvertierung macht, während in JS nur eine durchgeführt wird. Von der gewünschten Logik ist hier Perl näher dran, aber ob diese Logik immer gewünscht ist, ist die Frage. Aber vermutlich steht das irgendwo
perl -e 'print !!("0"&&"1")'
> ist false
>
> ~~~javascript
javascript:alert(!!("0"&&"1"))
>
ist true
Faszinierend!
Wie gesagt, nicht die und-Verknüpfung ist hier entscheidend, sondern der Unterschied von !"0"
javascript:alert(!"0")
=> false
print !'0' ? 'true' : 'false';
=> true
Struppi.
Hallo,
print !'0' ? 'true' : 'false';
=> true
Nein, false
perl -e 'print !!("0"&&"1")'
> > ist false
> >
> > ~~~javascript
javascript:alert(!!("0"&&"1"))
> >
ist true
Faszinierend!
Ja: Ein String, der etwas enthält, was kein Whitespace ist, konvertiert in JavaScript immer zu true.
Innerhalb von Strings wird fast nichts interpretiert, d.h. eine Null ist dort ein Zeichen wie jedes andere (keine Zahl), daher true
.
Aber:
alert( "\r\n"==false ); =>true
alert( !!"\r\n" ); =>false
Letzteres verstehe, wer will...
Gruß, Don P
Sorry,
Mein letztes Posting ist Quatsch, d.h. false
.
Aber das ist schon seltsam:
alert( "\r\n"==false ); =>true
alert( !!"\r\n"==false ); =>false, aber wieso?
Gruß, Don P
Aber das ist schon seltsam:
alert( "\r\n"==false ); =>true
Hier wird ein String mit einem bool'schen Wert verglichen.
alert( !!"\r\n"==false ); =>false, aber wieso?
[/code]
Hier zwei Bool'sche werte.
"\r\n" wird zu true
!"\r\n" wird zu false
!!"\r\n" wird zu true
true == false => false
Struppi.
Hallo,
Aber das ist schon seltsam:
alert( "\r\n"==false ); =>trueHier wird ein String mit einem bool'schen Wert verglichen.
Ja, und der Vergleich ergibt true, d.h. "\r\n" wird zu false (nur Whitespace), und somit
false==false =>true
alert( !!"\r\n"==false ); =>false, aber wieso?
Hier zwei Bool'sche werte.
"\r\n" wird zu true
Aber oben war es doch false...
!!"\r\n" wird zu true
Das müsste doch dann auch wieder false ergeben
Verstehe ich nicht.
Gruß, Don P
Aber das ist schon seltsam:
alert( "\r\n"==false ); =>trueHier wird ein String mit einem bool'schen Wert verglichen.
Ja, und der Vergleich ergibt true, d.h. "\r\n" wird zu false (nur Whitespace), und somit
false==false =>true
Nein, bei einem Vergleich wird jeder Wert, der kein Leerstring ist, zu einem true:
javascript:alert('\n'?true:false);
=> true
Bei einer Umwandlung sieht es anders aus.
alert( !!"\r\n"==false ); =>false, aber wieso?
Hier zwei Bool'sche werte.
"\r\n" wird zu true
Aber oben war es doch false...
Oben wurde er nicht explizit umgewandelt.
Verstehe ich nicht.
Die Frage ist wohl, wann ein Wert umgewandelt wird, also welcher Operator zuerst greift.
Struppi.
Hallo,
Nein, bei einem Vergleich wird jeder Wert, der kein Leerstring ist, zu einem true:
javascript:alert('\n'?true:false);
=> true
Das ist aber sehr verwirrend. Wie kann dann das sein:
alert( '\n'==false );
=>true
Hier muss doch '\n' auch zuerst umgewandelt werden, bevor es mit false verglichen wird, und JS behauptet hier doch ganz klar '\n'==false
!
Bei einer Umwandlung sieht es anders aus.
Micht wirklich: Wenn ich explizit umwandle:
alert( !'\n'==false );
=>true
JS behauptet hier also auch das Gegenteil,nämlich !'\n'==false
Daraus folgt messerschaf:
'\n' == !'\n'
und siehe:
alert( '\n' == !'\n' );
=> true !!
*kopfkratz* – Da ist doch etwas faul...
Gruß, Don P
Nein, bei einem Vergleich wird jeder Wert, der kein Leerstring ist, zu einem true:
javascript:alert('\n'?true:false);
=> trueDas ist aber sehr verwirrend. Wie kann dann das sein:
alert( '\n'==false );
=>true
Also die Spezifikation sagt:
11.9.3 The Abstract Equality Comparison Algorithm
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.[...]
15.[...]
16.[...]
17.[...]
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).
eigentlich steht da, dass der Boolean Wert mit toNumber() umgewandelt wird, das ist entweder ein Druckfehler oder ich weiß es nicht, aber das würde die ganzen Merkwürdigkeiten erklären:
Der String wird bei einem Vergleich zu einer Zahl umgewandelt. Während der Not-Operator die Funktion toBool() aufruft. Mit einem unterschiedlichen Ergebnis.
alert(
Number('\n') + '==false => ' + (Number('\n') == false)
+ '\n'
+ !'\n' + '==true => ' + (!'\n' == true)
);
*kopfkratz* – Da ist doch etwas faul...
Vermutlich.
Struppi.
Also die Spezifikation sagt:
11.9.3 The Abstract Equality Comparison Algorithm
The comparison x == y, where x and y are values, produces true or false. Such a comparison is
performed as follows:
- If Type(x) is different from Type(y), go to step 14.
[...]
14.[...]
15.[...]
16.[...]
17.[...]- If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
- If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
eigentlich steht da, dass der Boolean Wert mit toNumber() umgewandelt wird, das ist entweder ein Druckfehler oder ich weiß es nicht, aber das würde die ganzen Merkwürdigkeiten erklären:
http://www.united-coders.com/matthias-reuter/all-about-types-part-2
Soweit hab ich gar nicht gwagt zu denken - der Boolean Wert wird wirklich zu einer Zahl umgewandelt.
Struppi.
Hallo,
Soweit hab ich gar nicht gwagt zu denken - der Boolean Wert wird wirklich zu einer Zahl umgewandelt.
Wow. Ich wollte es jetzt doch ganz genau wissen. Es sieht so aus:
Zunächst für !'\n'==false
- If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
x ist hier mit !'\n'
ein boolescher Wert, der sich daraus ergibt, dass zunächst der NOT Operator !
auf den String '\n'
angewendet wird.
Die Spezifikation sagt dazu für einen String:
11.4.9 Logical NOT Operator ( ! )
The production UnaryExpression : ! UnaryExpression is evaluated as follows:
1. Evaluate UnaryExpression.
2. Call GetValue(Result(1)).
Das liefert den String.
3. Call ToBoolean(Result(2)).
und ToBoolean sagt:
"The result is false if the argument is the empty string (its length is zero); otherwise the result is true."
Also konvertiert '\n' hier zu true
, wie du oben schon richtig angemerkt hast.
4. If Result(3) is true, return false.
Fertig: Das Ergebnis ist also false
für !'n'
.
Schließlich werden die beiden booleschen Werte verglichen:
- If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
Passt: !'\n'==false
Ok, und nun der andere Fall: '\n'==false
Hier greift
- If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Tatsächlich: Der Boolesche Wert konvertiert erst zu einer Zahl, d.h. zu 0 für false
.
Dann wird der String mit dieser Zahl verglichen:
17.If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
ToNumber() wird jetzt auch auf den String angewendet, nach einer speziellen Grammatik, wobei Whitespace berücksichtigt wird (siehe 9.3.1 in der Spezifikation).
Für einen String, der nur Whitespace enthält, ergibt das 0.
Passt: '\n'==false
Somit haben wir den paradoxen Fall, dass tatsächlich gilt:
'\n' == !'\n'
sowie auch !'\n' == '\n'
Gruß, Don P
Hallo,
Man also einen String s, der nur Whitespace enthält, dadurch erkennen, dass gilt s==!s
tss...
Beweis:
var stringInfo = function(s) {
if( s == !s ) {alert('Der String enthält nur Whitespace.');}
else {alert('Der String enthält etwas anderes als nur Whitespace, oder ist leer.');}
};
var a = ' \n\r\t ', b = '', c = 'Text';
stringInfo(a); stringInfo(b); stringInfo(c);
Schön schön, aber wer braucht sowas?
Ich halte es für einen Bug. Eine solche Unlogik würde man doch keiner Programmiersprache zutrauen...
Gruß, Don P
Hi,
Man also einen String s, der nur Whitespace enthält, dadurch erkennen, dass gilt
s==!s
tss...
Schön schön, aber wer braucht sowas?
Ich halte es für einen Bug.
ich nicht, denn ich bin ziemlich sicher, du testest *nicht* im IE, sondern vermutlich im Firefox. Ich kann das von dir beschriebene Phänomen aber auch in IE5.5 und IE6.0 reproduzieren.
Ich kann mir nicht vorstellen, dass die Mozilla Foundation und Microsoft unabhängig voneinander denselben Bug produzieren. Es sei denn, das Verhalten ergäbe sich durch unlogische oder widersprüchliche Definitionen in der Spezifikation.
Eine solche Unlogik würde man doch keiner Programmiersprache zutrauen...
Nicht absichtlich. Oder wenn doch, würde man es wenigstens als ungewöhnlichen Sonderfall dokumentieren.
Ciao,
Martin
Hallo,
ich nicht, denn ich bin ziemlich sicher, du testest *nicht* im IE, sondern vermutlich im Firefox.
Genau.
Ich kann das von dir beschriebene Phänomen aber auch in IE5.5 und IE6.0 reproduzieren.
Das wundert mich nicht. Es muss sich wohl irgendwie aus der ECMAScript-Spezifikation ergeben. Ein Bug in der Spezifikation vielleicht...
Eine solche Unlogik würde man doch keiner Programmiersprache zutrauen...
Nicht absichtlich. Oder wenn doch, würde man es wenigstens als ungewöhnlichen Sonderfall dokumentieren.
Das haben wir ja jetzt hier nachgeholt :)
Vielleicht ist es ja doch ganz nützlich, denn mit der Ausdruck !s||(s==!s)
[TM] kann man nun von einem String s ganz einfach feststellen, ob er Text enthält oder nicht. Wenn er keinen Text enthält, ergibt das true, sonst false.
Machen wir doch gleich Nägel mit Köpfen:
String.prototype.hasText = function() {return !(!this||(this==!this));};
Die Unlogik fängt an mir zu gefallen...
Gruß, Don P
Hallo,
Machen wir doch gleich Nägel mit Köpfen:
String.prototype.hasText = function() {return !(!this||(this==!this));};
Nur der Vollständigkeit halber, bevor der Thread im Archiv verschwindet:
Obige Methode ergibt leider auch dann false
, wenn eine oder mehrere aufeinanderfolgende Nullen im String enthalten sind, was ja eigentlich kein Whitespace ist, sondern eher Text. Man müsste sie daher so notieren:
String.prototype.hasText = function() {return !(this.indexOf('0')<0 && (!this||(this==!this)))};
Das ist schon nicht mehr so elegant :(.
Habe aber schon den ersten Fall gehabt, wo ich die neue String-Methode brauchen konnte :)
Gruß, Don P
Hallo,
Wieso interveniert hier niemand?
Statt
!(!this||(this==!this))
oder
!(this.indexOf('0')<0 && (!this||(this==!this)))
kann man doch einfach
`this!=0`{:.language-javascript}
bzw.
`!(this==0 && this.indexOf('0')<0)`{:.language-javascript}
schreiben. `s==!s`{:.language-javascript} ist also wirklich unbracuhbar, ein Spezialfall, der sich wohl eher zufällig so ergeben hat bei der Spezifikation von JavaScript.
Gruß, Don P
Wieso interveniert hier niemand?
Ich weiß nicht, wofür man sowas braucht. Wenn ich testen will ob in einer Zeichenkette Whitespacezeichen enthalten sind, nehme ich einen Regulären Ausdruck, ist für mich einfacher nachzuvollziehen.
schreiben.
s==!s
ist also wirklich unbracuhbar, ein Spezialfall, der sich wohl eher zufällig so ergeben hat bei der Spezifikation von JavaScript.
Soweit ich das sehe, läßt sich dank dieser Spezifikation immer schreiben:
if(wert) ... oder if(!wert) .....
das ist nicht so selbstverständlich. In Perl z.b. hat man hier das Problem bei der Typenkonvertierung, dass z.b. if('0') unwahr ist.
Struppi.
Hallo,
Ich weiß nicht, wofür man sowas braucht. Wenn ich testen will ob in einer Zeichenkette Whitespacezeichen enthalten sind, nehme ich einen Regulären Ausdruck, ist für mich einfacher nachzuvollziehen.
Es geht mehr darum festzustellen, ob Text enthalten ist, d.h. ob ein nicht leerer String überhaupt druckbare Zeichen enthält. In Performancekritischen Anwendungen sind reguläre Ausdrücke ja nicht die beste Wahl.
Soweit ich das sehe, läßt sich dank dieser Spezifikation immer schreiben:
if(wert) ... oder if(!wert) .....das ist nicht so selbstverständlich. In Perl z.b. hat man hier das Problem bei der Typenkonvertierung, dass z.b. if('0') unwahr ist.
Stimmt. if(wert) ist schon mächtig :)
Gruß, Don P
Ich weiß nicht, wofür man sowas braucht. Wenn ich testen will ob in einer Zeichenkette Whitespacezeichen enthalten sind, nehme ich einen Regulären Ausdruck, ist für mich einfacher nachzuvollziehen.
Es geht mehr darum festzustellen, ob Text enthalten ist, d.h. ob ein nicht leerer String überhaupt druckbare Zeichen enthält. In Performancekritischen Anwendungen sind reguläre Ausdrücke ja nicht die beste Wahl.
Hast du das mal getestet? Dein Ausdruck ist nämlich, zumindest im Fx, langsamer (im IE ungefähr gleich, mehr Browser hatte ich noch nicht).
Struppi.
Hallo,
Hast du das mal getestet?
Nö.
Dein Ausdruck ist nämlich, zumindest im Fx, langsamer (im IE ungefähr gleich, mehr Browser hatte ich noch nicht).
Welcher Audruck jetzt? Habe ja mehrere angegeben.
Gruß, Don P
Hast du das mal getestet?
Nö.
Ich hab aber.
Dein Ausdruck ist nämlich, zumindest im Fx, langsamer (im IE ungefähr gleich, mehr Browser hatte ich noch nicht).
Welcher Audruck jetzt? Habe ja mehrere angegeben.
Naja, der fehlerfreie letzte.
Struppi.
Hallo,
Dein Ausdruck ist nämlich, zumindest im Fx, langsamer
/\S/.test(str)
ist also schneller? Ok, ist gekauft.
Danke, Don P