Raik: Unterschied zwischen null, false und 0

Hallo!

Ich habe beim Ausprobieren des Feature-Artikels "Auf Dateien mit JavaScript zugreifen" von Daniel Thoma Probleme mit dem Rückgabewert "null" des Applets gehabt.
http://aktuell.de.selfhtml.org/artikel/javascript/file-open/index.htm
Das zeilenweise Auslesen mit dem empfohlenen "while ((line = document.fileopener.readFile()) != null)" führte zu einem Fehler des Applets.
Nachdem ich es so probiert habe: "while (line = document.fileopener.readFile())", ging es.
Ebenfalls so: "var ende = new Boolean(false); while ((line = document.fileopener.readFile()) != ende)" .

Das brachte mich zu folgendem Versuch:

<script type=text/javascript>
d1= new Boolean(null);
d2= new Boolean(false);
d3= new Boolean(0);
d4= new Boolean();

if(d1==null){document.write('d1<br>')}
if(d2==false){document.write('d2<br>')}
if(d3==0){document.write('d3<br>')}

if(d4==0){document.write('d4==0<br>')}
if(d4==false){document.write('d4==false<br>')}
if(d4==null){document.write('d4==null<br>')}

if(d1==d2){document.write('d1==d2<br>')}
if(d2==d3){document.write('d2==d3<br>')}
if(d3==d4){document.write('d3==d4<br>')}
</script>

Im IE6 gibt es als Ergebnis:
d2
d3
d4==0
d4==false

Mich würden die Ergebnisse anderer Browser interessieren.
Wäre nett, wenn ihr die hier mit reinpostet.

freundl. Grüsse aus Berlin, Raik

  1. Mich würden die Ergebnisse anderer Browser interessieren. Wäre nett, wenn ihr die hier mit reinpostet.

    es gibt ganz viele browser, die kann man sich runterladen und installieren zum testen: http://www.mozilla.org (mozilla 1.6, und firefox 0.8) http://www.netscape.com http://www.opera.com http://lynx.browser.org/ (der beste und schnellste ;-))

    aber ich will ja nicht so sein: mein firefox gibt folgendes aus d2 d3 d4==0 d4==false

    (schätze mal das wird mozilla, sowie netscape auch tun)

  2. gruss Raik,

    ...
    Das brachte mich zu folgendem Versuch:
    ...

    javascript ist nur lose typisiert;

    jeder js-interpreter wertet den typ eines datums auch abhaengig
       von dessen umgebung aus;

    Dein beispiel nimmt sich den konstruktor Boolean vor, "gefuettert"
       wird er mit argumenten jeweils unterschiedlichen typs;

    boolean-objekte koennen aber nur die werte false bzw. true
       einnehmen - der konstruktor bewertet die argumente dahingehend;

    ohne argument oder mit einem undefinierten argument wird der
       konstruktor immer den wert false liefern, aber auch die argumente
       0, null und "" werden dahingehend ausgewertet - schon der einsatz
       jeden anderen wertes, und sei es z.b. "0" liefert ein boolean-objekt
       mit dem wert true zurueck;

    fuer Dein gegebenes beispiel bedeutet dies, dass Deine variablen
       d1, d2, d3 bzw. d4 boolean-objekte jeweils mit dem wert false sind -
       Du trittst also bei deren spaeteren einsatz immer mit deren false-
       werten an, die Du dann auf die werte null, false und 0 vergleichst:

    d1: (false == null)  // false;
       d2: (false == false) // true;
       d3: (false == 0)     // true;

    d4: (false == 0)     // true; (das hatten wir grade)
       d4: (false == false) // true; (kurz davor dies auch)
       d4: (false == null)  // false;( ... siehe oben ... )

    a) ein null-wert bleibt auch im kontext eines boolean-wertes null;
       b) boolean-werte koennen problemlos miteinander verglichen werden;
       c) der wert 0 vom typ number konvertiert im kontext eines boolean-wertes zu false;
       d) der wert "" vom typ string konvertiert im kontext eines boolean-wertes zu false;

    nach dieser ausfuehrung mag es verwirren, warum fuer
       den auf den ersten blick eindeutigen fall von:

    d1:false, d2:false, d3:false, d4:false

    nun nicht (d1==d2==d3==d4) gleich true gelten soll,
       obwohl (false==false) gleich true ja offensichtlich gilt.

    an dieser stelle stolperst Du ueber das problem, objekte aber nicht
       deren werte miteinander zu vergleichen, denn Du hast den Boolean-
       konstruktor einem einfachen boolean-literal vorgezogen - der beweis:

    var d5=false, d6=false, d7=new Boolean(), d8=new Boolean();
       alert(typeof(d5)) // boolean;
       alert(typeof(d6)) // boolean;
       alert(typeof(d7)) // object;
       alert(typeof(d8)) // object;

    alert(d5 == d6)   // true;
       alert(d5 == d8)   // true;
       alert(d6 == d7)   // true;
       //ABER:
       alert(d7 == d8)   // false;

    Du kannst d5 und d6 untereinander, beide aber auch mit d7 bzw. d8
       vergleichen, da die werte d5 und d6 beim vergleich mit den objekten
       d7 und d8 den kontext fuer eine typenkonvertierung bieten - objekte
       hingegen lassen sich weder mit dem gleichheits[==] - noch mit dem
       identitaets[===]-operator vergleichen, dazu beduerfte es der noch
       zu schreibenden prototypen methode "Object.equals";

    in diesem fall kann man aber auch abhilfe schaffen, indem man die
       fuer objekte eingebaute methode "toString" auf die boolean-objekte
       wie folgt anwendet:

    alert(d7.toString());
       alert(d8.toString());
       alert(d7.toString()==d8.toString());

    fazit:
       * das von Dir beschriebene verhalten ist ein grundsaetzliches;
       * jetzt ist es vielleicht verstaendlicher, warum ich in meinen
         ausfuehrungen so auf typ, wert und objekt herumgeritten bin;

    regeln:
       * die "primitiven" typen boolean, number und string kommen als
         solche nur ueber ihre literalschreibweise zur anwendung:

    var bool = true;
         var num = 123;
         var str = "hi";

    * konstruktoren erzeugen objekte, denen werte zugewiesen sind:
         new Boolean(), new String() und new Number() sind nicht
         "primitiv" im sinne der ersten regel (und eigentlich gibt es
         diese terminologie in javascript auch ueberhaupt nicht [aber
         trotzdem wird der typeof-operator sehr oft bemueht]);

    * besondere aufmerksamkeit sollte man den einfachen vergleichen
         [==] auf 0, null und "" widmen - typenkonvertierung verhindert
         hier nur der identitaetsoperator[===]; im gleichen zusammenhang
         ist auch darauf zu achten, dass jegliche pruefung auf die existenz
         von objekten fehlschlaegt "if (myObject) {...}", wenn diese einen
         der obigen werte haben; der "if"-block wird nie abgearbeitet,
         obschon es ein definiertes "myObject" gibt;

    * gute type-detection ist die grundlage fuer eine schnelle und
         fehlerfreie entwicklung in schwach typisierten sprachen wie
         javascript:
         http://www.pseliger.de/jsExtendedApi/jsApi.Object.typeDetection.dev.js
         http://www.pseliger.de/jsExtendedApi/jsApi.Object.typeDetection.js

    credits:
       * vor einem jahr las ich http://www.crockford.com/javascript/remedial.html,
         sodass Douglas Crockford in dieser hinsicht als mein lehrmeister betrachtet
         werden kann;

    gute nacht fuer mich - guten morgen fuer Euch - peterS. - pseliger@gmx.net

    --
    sh:| fo:) ch:? rl:| br:& n3:} n4:# ie:| mo:{ va:| de:[ zu:] fl:) ss:) ls:& js:)
    1. Hallo, peter!

      Vielen Dank für diese hochinteressanten, lehrreichen Ausführungen! :-)

      Dann hätte ich noch eine frage an die Java-experten:
      die ursprüngliche Schreibweise:

      public void setFile(String file)
      {
         /* file wird verwendet ... */
      }

      Da das beim Einbau des Security-Managers einen Fehler gibt (file muss final sein), hab ich es so gelöst:

      public String uri;
      public String returnUri()
      {
      return uri;
      }
      public void setFile(String file)
      {
      uri = file;
           AccessController.doPrivileged(new PrivilegedAction() {
              public Object run() {
                  String filea = returnUri();
                  /* filea wird verwendet ... */
                  return null;
              }
          });
      }

      Ist meine Lösung zu umständlich oder gar falsch ?
      Wie würde das ein Profi lösen?

      freundl. Grüsse aus Berlin, Raik

    2. Hi,

      alert(typeof(d5)) // boolean;
         identitaets[===]-operator vergleichen, dazu beduerfte es der

      Der Vollständigkeit sei nach erwähnt, daß typeOf ab JS 1.1, === erst ab JS 1.2 vorhanden sind und somit in älteren Versionen Fehler erzeugen.

      Gruß, Cybaer

      1. gruss Cybaer,

        Der Vollständigkeit sei nach erwähnt, daß typeOf ab JS 1.1, === erst ab JS 1.2 vorhanden sind und somit in älteren Versionen Fehler erzeugen.

        wann stoesst man denn heute noch auf einen client,
           der aelter als netscape navigator 3 oder msie 3 ist?
          (,denn JavaScript 1.1 bzw. JScript1 und damit auch der
            operator typeof wurden dort jeweils schon unterstuetzt)

        by(t)e by(t)e - peterS. - pseliger@gmx.net

        --
        sh:| fo:) ch:? rl:| br:& n3:} n4:# ie:| mo:{ va:| de:[ zu:] fl:) ss:) ls:& js:)
        1. Hi,

          wann stoesst man denn heute noch auf einen client,
             der aelter als netscape navigator 3 oder msie 3 ist?
            (,denn JavaScript 1.1 bzw. JScript1 und damit auch der
              operator typeof wurden dort jeweils schon unterstuetzt)

          Das weiß man nicht. Oder hättest Du gewußt, daß der integrierte Browser eines *neuen* PalmOS-Keyboards mit WLAN (Mischung zw. PalmTop und vollwertiger Tastatur - s. aktuelle c't) zwar JavaScript beherrscht, aber nur JS 1.3?

          Auch bei einigen Unis/Behörden/Firmen/Otto-Normal-Usern gibt es eigentlich veraltete Browser (sogar den IE 3, weil der bei einer Win95-Version dabei war - sogar in der Erst-Verson mit JS 1.0).

          Man muß ja nicht unbedingt darauf Rücksicht nehmen (kommt auch auf die Zielgruppe an), aber man darf sich dessen wenigstens bewußt sein - schadet ja nicht. IMHO sollte man allerdings generell seine Scripte so bauen, daß sie keine Fehler produzieren. Das schließt die Nutzung von neueren und neuesten Funktionen ja auch überhaupt nicht aus ...

          Gruß, Cybaer

          --
          Hinweis an Fragesteller: Fremde habe ihre Freizeit geopfert, um Dir zu helfen. Helfe auch Anderen: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
          1. hallo again Cybaer,

            Man muß ja nicht unbedingt darauf Rücksicht nehmen ... aber man
            darf sich dessen wenigstens bewußt sein ... IMHO sollte man
            allerdings generell seine Scripte so bauen, daß sie keine Fehler
            produzieren. Das schließt die Nutzung von neueren und neuesten
            Funktionen ja auch überhaupt nicht aus ...

            volle zustimmung - tschoe - peterS. - pseliger@gmx.net

            --
            sh:| fo:) ch:? rl:| br:& n3:} n4:# ie:| mo:{ va:| de:[ zu:] fl:) ss:) ls:& js:)