LanX!: JS Typprobleme

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

  1. 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

    1. 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.

      1. 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

        1. 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: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.

          1. Hallo,

            print !'0' ? 'true' : 'false'; => true

            Nein, false

            perl -e 'print !!("0"&&"1")'

            ist false

            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

            1. 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

              1. 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.

                1. Hallo,

                  Aber das ist schon seltsam:
                  alert( "\r\n"==false ); =>true

                  Hier 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

                  1. Aber das ist schon seltsam:
                    alert( "\r\n"==false ); =>true

                    Hier 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.

                    1. 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

                      1. 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

                        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.

                        1. 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:

                          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.

                          1. 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

                            1. 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:

                            1. 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

                            1. 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

                    2. 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

                      1. 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

                        --
                        Finanztipp:
                        Leihen Sie sich Geld von einem Pessimisten.
                        Er rechnet sowieso nicht damit, dass er es zurückbekommt.

                        1. 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

                          1. 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

                            1. Hallo,

                              Wieso interveniert hier niemand?

                              Statt

                              !(!this||(this==!this))

                              oder

                              !(this.indexOf('0')<0 && (!this||(this==!this)))

                              kann man doch einfach
                              this!=0
                              bzw.
                              !(this==0 && this.indexOf('0')<0)

                              schreiben. s==!s ist also wirklich unbracuhbar, ein Spezialfall, der sich wohl eher zufällig so ergeben hat bei der Spezifikation von JavaScript.

                              Gruß, Don P

                              1. 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.

                                1. 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

                                  1. 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.

                                    1. 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

                                      1. 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.

                                        1. Hallo,

                                          Dein Ausdruck ist nämlich, zumindest im Fx, langsamer

                                          /\S/.test(str)
                                          ist also schneller? Ok, ist gekauft.

                                          Danke, Don P