zonk: Typecasting und Prototypen von Objekten

Ich verstehe nicht, wie toString und valueOf funktionieren.

function o(){}

o.prototype.toString = function() {
return "o";
};

o.prototype.valueOf = function() {
return "1";
};

o1 = new o();

a. alert("Das Objekt " + o1);
b. alert(o1);
c. alert(o1 + o1);

a. Ich würde für a denken, es ist "Das Objekt o", ist aber "Das Objekt 1"
b. Wie ich denke "o"
c. Ich erwarte 2: trifft zu.

Wieso wird bei a. o1 nicht mit toString in eine Zeichenkette umgewandelt, in b. aber schon? alert("30" + 30) wandelt doch auch 30 in die Zeichenkette "30" mit dem Ergebnis 3030 um.

  1. Hallo zonk,

    Ich verstehe nicht, wie toString und valueOf funktionieren.

    zusammen in einem Objekt nicht, wenn Du JS die Wahl überlässt. Hier musst Du wohl auf nummer sicher gehen und die Methoden des Objektes explizit aufrufen:

    alert(o1.toString()+" "+o1.valueOf());

    valueOf() würde ich auch eher mit Zahlen in Verbindung bringen wollen als mit Zeichenketten...

    Mit freundlichem Gruß
    Micha

    1. Hallo zonk,

      Ich verstehe nicht, wie toString und valueOf funktionieren.
      zusammen in einem Objekt nicht, wenn Du JS die Wahl überlässt. Hier musst Du wohl auf nummer sicher gehen und die Methoden des Objektes explizit aufrufen:

      Aber wieso das so ist, weißt Du auch nicht?

      Ähnlich ist es hier:

      Number.prototype.toString = function(){
      return 1000;
      };

      z1 = new Number(10);
      z2 = 10;

      alert(z1);  // ist 1000
      alert(z2);  // ist 10

      Hingegen

      Function.prototype.toString = function() {
      return "f";
      };

      f1 = new Function("");
      function f2(){}

      alert(f1); // ist f
      alert(f2); // ist f

      Scheinbar haben primitive Zahlen eigene toString-Methoden!?

      1. Hallo zonk,

        Aber wieso das so ist, weißt Du auch nicht?

        Nein, das könnte jedoch Matthias (molily) wissen.

        Scheinbar haben primitive Zahlen eigene toString-Methoden!?

        Nein aber alle Objekte haben diese wohl und nur dort kannst Du sie überschreiben. Aus diesem Grund wird Dein z2 auch als 10 ausgegeben und nicht als 1000.

        Mit freundlichem Gruß
        Micha

        1. Scheinbar haben primitive Zahlen eigene toString-Methoden!?
          Nein aber alle Objekte haben diese wohl und nur dort kannst Du sie überschreiben. Aus diesem Grund wird Dein z2 auch als 10 ausgegeben und nicht als 1000.

          Mit freundlichem Gruß
          Micha

          Das kann sein. Hinzufügen kann man aber Methoden, die dann auch mit primitiven Werten funktionieren.

        2. Hallo,

          Nein, das könnte jedoch Matthias (molily) wissen.

          Ich lern auch nur von Tims Recherchen. ;)

          Mathias

      2. Hallo zonk,

        Ähnlich ist es hier:

        Ich versuch's mal auch hier zu erklären, vorsicht Vorkenntnis erfordlich. ;)

        Number.prototype.toString = function(){
        return 1000;
        };
        z1 = new Number(10);

        z1 ist ein Number-Objekt.

        z2 = 10;

        z2 ist ein Wert vom Typ Number.

        alert(z1);  // ist 1000

        alert() ruft (vermutlich) die interne Methode ToString auf. Für das Number-Objekt ruft diese die interne Methode ToPrimitive mit dem Hint String auf was irgendwann dann in einem Aufruf Deiner toString-Methode landet.

        alert(z2);  // ist 10

        Für einen Wert vom Typ number hingegen wird aus der internen Funktion ToString die interne Routine zum Umwandeln von Zahlen in Strings aufgerufen, spezifiziert als ToString Applied to the Number Type. An keiner Stelle wird dieser Number-Wert in ein Number-Objekt umgewandelt, dessen toString-Methode genutzt werden könnte.

        Manchmal glaube ich, diese Trennung zwischen primitiven Werten und Objekten richtet mehr Schaden an, als sie gutes tut.

        f1 = new Function("");
        function f2(){}

        Functions sind immer Objekte, egal wie deren Erstellung notiert wird.

        Scheinbar haben primitive Zahlen eigene toString-Methoden!?

        Ja.

        Tim

        1. Hallo Tim,

          alert() ruft (vermutlich) die interne Methode ToString auf. Für das Number-Objekt ruft diese die interne Methode ToPrimitive mit dem Hint String auf was irgendwann dann in einem Aufruf Deiner toString-Methode landet.

          alert(z2);  // ist 10

          Für einen Wert vom Typ number hingegen wird aus der internen Funktion ToString die interne Routine zum Umwandeln von Zahlen in Strings aufgerufen, spezifiziert als ToString Applied to the Number Type. An keiner Stelle wird dieser Number-Wert in ein Number-Objekt umgewandelt, dessen toString-Methode genutzt werden könnte.

          Sehe ich das richtig, primitive Werte haben interne Funktionen, Objekte hingegen Methoden?

          Wie ist es bei Eigenschaften?

          Z.B.

          a = ["Ein", "Array"];
          L = a.length;

          Ist length wirklich eine Eigenschaft von a (auf die man nur bei for-in keinen Zugriff hat)? Was sind lokale Variablen oder das Array arguments bei Funktionen?

          Manchmal glaube ich, diese Trennung zwischen primitiven Werten und Objekten richtet mehr Schaden an, als sie gutes tut.

          Es ist auf jeden Fall verwirrend. Die Frage ist überhaupt, wozu es die Objekte String, Number, Function und Boolean geben muß, noch dazu wenn sich deren Handling von den primitiven Datentypen unterscheidet! Ok, bei Funktionen kann man mit Phantasie noch einen Zweck in dynamisch generierten Funktionen sehen.

          f1 = new Function("");
          function f2(){}

          Functions sind immer Objekte, egal wie deren Erstellung notiert wird.

          Ja, ich weiß. Der Knackpunkt bleibt, wieso Objekte bei Verkettung mit einer Zeichenkette keinen Stringkontext erzeugen.

          Noch mal zur Frage, welchen Status lokale Variablen haben. Sind es (statische oder temporäre) Eigenschaften des Funktionsobjekts, zu denen man nur während der Ausführung Zugriff hat (und dann auch nicht über die Objektoperatoren . und []), oder sind es reine Datenbereiche, die vom Interpreter in einem Stack verwaltet werden?

          1. Hallo,

            Sehe ich das richtig, primitive Werte haben interne Funktionen, Objekte hingegen Methoden?

            Die Frage verstehe ich nicht.

            Wie ist es bei Eigenschaften?

            Z.B.

            a = ["Ein", "Array"];
            L = a.length;

            Ist length wirklich eine Eigenschaft von a (auf die man nur bei for-in keinen Zugriff hat)?

            Ja, klar.

            Was sind lokale Variablen oder das Array arguments bei Funktionen?

            Lokale Variablen hängen an einem internen »lokale Variablen«-Objekt, auf das man aber nicht direkt zugreifen kann. arguments ist eine solche »lokale Variable«.

            Die Frage ist überhaupt, wozu es die Objekte String, Number, Function und Boolean geben muß, noch dazu wenn sich deren Handling von den primitiven Datentypen unterscheidet!

            Mein Standardspruch: Objekte haben Identität, Primitives keine.
            Objekte sind nur mit sich selbst identisch und somit unvergleichbar (Objekt == AnderesObjekt ergibt immer false, Objekt1 === Objekt2 sowieso). Das Objekt wird behandelt, als ob sein Wert komplex wäre. Bei der Übergabe an Funktionen werden sie deshalb nicht einfach kopiert, sondern immer als Referenz übergeben.
            Dieses Verhalten *kann* erwünscht sein, daher kann man Strings und Numbers auch als Objekte anlegen. Außerdem ist die Unterscheidung Primitives vs. Objects bei String, Number und Boolean auch nötig, um intern die prototypische Vererbung und andere Features umzusetzen. Ein Primitive verhält sich ja in vielen Kontexten wie ein Objekt.

            Noch mal zur Frage, welchen Status lokale Variablen haben. Sind es (statische oder temporäre) Eigenschaften des Funktionsobjekts zu denen man nur während der Ausführung Zugriff hat (und dann auch nicht über die Objektoperatoren . und []),

            Nein. Globale Variablen sind window-Eigenschaften, lokale sind Eigenschaften eines internen Objektes.

            oder sind es reine Datenbereiche, die vom Interpreter in einem Stack verwaltet werden?

            Siehe oben. Variable Instantiation

            Mathias

            1. Hallo Mathias,

              Sehe ich das richtig, primitive Werte haben interne Funktionen, Objekte hingegen Methoden?

              Die Frage verstehe ich nicht.

              Wie es nicht gemeint war: Funktionen sind ja nutzerseitig nichts anderes als Objekte. Was ich meinte: Methoden = interner JS-Code (oder auch in der eigentlichen Quelltextsprache), der an Objekte gebunden ist und den man überschreiben kann. Funktionen = Code, der in der Sprache, in welcher JS geschrieben ist (welche ist das überhaupt?) ausgeführt wird, also der eigentlich Interpreterkern.

              Wie ist es bei Eigenschaften?

              Z.B.

              a = ["Ein", "Array"];
              L = a.length;

              Ist length wirklich eine Eigenschaft von a (auf die man nur bei for-in keinen Zugriff hat)?

              Ja, klar.

              »»

              Ganz sicher? Es könnte ja auch einen globalen Speicherbereich geben, der vom Interpreter verwaltet wird, wo alle length-Eigenschaften aller Arrays in einer selbst array- oder objektartigen Struktur bzw. tatsächlich als Array oder Objekt, aber in der eigentlichen Sprache, in der der Interpreter geschrieben ist, liegen.

              Und wenn length tatsächlich eine Eigenschaft von a ist, so muß sie besonders geschützt sein. Man kann sie ja zum Beipiel nicht mit einem String überschreiben. Wie wäre dieser Schutz aufgebaut? Eine internes Objekt, in der alle geschützten Eigenschaften und Methoden aufgelistet sind?

              Was mich interessiert ist das Handling solcher interner oder vorimplentierter Eigenschaften und Methoden, dazu findet man im Web aber kaum was.

              Was sind lokale Variablen oder das Array arguments bei Funktionen?

              Lokale Variablen hängen an einem internen »lokale Variablen«-Objekt, auf das man aber nicht direkt zugreifen kann. arguments ist eine solche »lokale Variable«.

              Ein Objekt für alle Funktionen? Sind die lokalen Variablen dann nur temporär (persistente Eigenschaften würden den Speicher zumüllen).

              Die Frage ist überhaupt, wozu es die Objekte String, Number, Function und Boolean geben muß, noch dazu wenn sich deren Handling von den primitiven Datentypen unterscheidet!

              Mein Standardspruch: Objekte haben Identität, Primitives keine.
              Objekte sind nur mit sich selbst identisch und somit unvergleichbar (Objekt == AnderesObjekt ergibt immer false, Objekt1 === Objekt2 sowieso). Das Objekt wird behandelt, als ob sein Wert komplex wäre. Bei der Übergabe an Funktionen werden sie deshalb nicht einfach kopiert, sondern immer als Referenz übergeben.
              Dieses Verhalten *kann* erwünscht sein, daher kann man Strings und Numbers auch als Objekte anlegen. Außerdem ist die Unterscheidung Primitives vs. Objects bei String, Number und Boolean auch nötig, um intern die prototypische Vererbung und andere Features umzusetzen. Ein Primitive verhält sich ja in vielen Kontexten wie ein Objekt.

              Richtig, aber in anderen Sprachen bedarf es dazu nicht solch verwirrender Unterscheidungen und "doppelter" Datentypen. In PHP werden seit Version 5 Objekte standardmäßig als Referenzen übergeben. Will man by value kopieren, gibt es spezielle Befehle. Umgekehrt kann man einfache Datentypen, die standardmäßig als Wert kopiert, verglichen oder übergeben werden, durch Voranstellen von & per Referenz kopieren usw.

              Diese Implementierung finde ich intuitiver. Deswegen denke ich, "doppelte" Datentypen sind eigentlich nicht nötig.

              Noch mal zur Frage, welchen Status lokale Variablen haben. Sind es (statische oder temporäre) Eigenschaften des Funktionsobjekts zu denen man nur während der Ausführung Zugriff hat (und dann auch nicht über die Objektoperatoren . und []),

              Nein. Globale Variablen sind window-Eigenschaften, lokale sind Eigenschaften eines internen Objektes.

              »»

              Ja, aber früher konnte man ja über funktionsname.lokaleVariable auf sie zugreifen. Ich glaube mit arguments geht das immer noch. Ich nehme an, dann verweist funktionsname.arguments auf das Array arguments in dem internen Objekt. Und bei length muß über funktionsname.length zugegriffen werden (also ist das wahrscheinlich keine Eigenschaft des internen Objektes, sondern eine geschützte Eigenschaft der Funktion).

              1. Hallo,

                Sehe ich das richtig, primitive Werte haben interne Funktionen, Objekte hingegen Methoden?
                Wie es nicht gemeint war: Funktionen sind ja nutzerseitig nichts anderes als Objekte. Was ich meinte: Methoden = interner JS-Code (oder auch in der eigentlichen Quelltextsprache), der an Objekte gebunden ist und den man überschreiben kann. Funktionen = Code, der in der Sprache, in welcher JS geschrieben ist (welche ist das überhaupt?) ausgeführt wird, also der eigentlich Interpreterkern.

                Verstehe die Unterscheidung immer noch nicht. ;)
                Primitive Werte »haben« genauso Methoden insofern, dass sie intern ständig in die entsprechenden Objekte »umgewandelt« werden.

                Es könnte ja auch einen globalen Speicherbereich geben, der vom Interpreter verwaltet wird, wo alle length-Eigenschaften aller Arrays in einer selbst array- oder objektartigen Struktur bzw. tatsächlich als Array oder Objekt, aber in der eigentlichen Sprache, in der der Interpreter geschrieben ist, liegen.

                Keine Ahnung, wie das hinter den Kulissen gelöst ist - Objekte, wie man ihnen in JavaScript begegnen, sind natürlich auch nur Abstraktionen. Wie da die C++-Umsetzung aussieht, weiß ich nicht, aber der Witz in JavaScript ist eben, dass man sich darüber auch wenig Gedanken machen muss. (Der Teil ist auch nirgendwo standardisiert. Warum auch.)

                Und wenn length tatsächlich eine Eigenschaft von a ist, so muß sie besonders geschützt sein.

                Siehe auch </archiv/2007/10/t159610/>
                Sie ist als DontEnum, DontDelete festgelegt.

                Man kann sie ja zum Beipiel nicht mit einem String überschreiben.

                Kann man schon versuchen. Wird aber ignoriert werden, weil der String keine sinnvolle Zahl ergibt:
                http://bclary.com/2004/11/07/ecma-262.html#a-15.4.5.1

                Lokale Variablen hängen an einem internen »lokale Variablen«-Objekt, auf das man aber nicht direkt zugreifen kann. arguments ist eine solche »lokale Variable«.

                Ein Objekt für alle Funktionen?

                Nein, jeder Function-Scope hat sein eigenes arguments-Objekt, siehe Link im letzten Posting.

                Sind die lokalen Variablen dann nur temporär (persistente Eigenschaften würden den Speicher zumüllen).

                Natürlich, solange ein Scope noch irgendwo »konserviert« ist (Stichwort Closures), existieren die lokalen Variablen, ansonsten werden sie sofort aus dem Speicher geräumt.
                »arguments« ist ja kein wirklich unabhängig vom Scope existierendes Objekt, sondern nur eine Zugriffsweise.

                in anderen Sprachen bedarf es dazu nicht solch verwirrender Unterscheidungen und "doppelter" Datentypen. In PHP werden seit Version 5 Objekte standardmäßig als Referenzen übergeben.

                PHP ist kein Vergleich, weil es keine konsequent objektorientierte Sprache ist. Das Problem ergibt sich nur in solchen. Ein String ist in PHP kein Objekt, hat keine Methoden und kann auch keine Member vom Prototyp erben.
                Ich denke mal eher, Java, Ruby oder Python wären in dieser Hinsicht mit JavaScript vergleichbare Sprachen, mit denen kenne ich mich aber überhaupt nicht aus. (Tiiim!)

                Ja, aber früher konnte man ja über funktionsname.lokaleVariable auf sie zugreifen.

                Mit Sicherheit nicht.

                Ich glaube mit arguments geht das immer noch.

                Ja, aber Funktionsname.arguments war mal von Netscape JavaScript eingeführt und ist jetzt deprecated, in ECMAScript ist arguments eine lokale Variable.

                Mathias

                1. Hallo,

                  Primitive Werte »haben« genauso Methoden insofern, dass sie intern ständig in die entsprechenden Objekte »umgewandelt« werden.

                  Das hatte ich bei der Antwort von Tim anders verstanden (Stichworte: eigene toString()-Methoden, toPrimitive()).

                  Es könnte ja auch einen globalen Speicherbereich geben, der vom Interpreter verwaltet wird, wo alle length-Eigenschaften aller Arrays in einer selbst array- oder objektartigen Struktur bzw. tatsächlich als Array oder Objekt, aber in der eigentlichen Sprache, in der der Interpreter geschrieben ist, liegen.

                  Keine Ahnung, wie das hinter den Kulissen gelöst ist - Objekte, wie man ihnen in JavaScript begegnen, sind natürlich auch nur Abstraktionen. Wie da die C++-Umsetzung aussieht, weiß ich nicht, aber der Witz in JavaScript ist eben, dass man sich darüber auch wenig Gedanken machen muss. (Der Teil ist auch nirgendwo standardisiert. Warum auch.)

                  Ok, das hatte ich nicht bedacht. EcmaScript ist ja nur sozusagen ein standardisiertes "Interface", das völlig unterschiedlich im "Backend" implementiert werden kann. Könnte also auch jemand herkommen und z. B. einen Interpreter in VB schreiben.

                  Und wenn length tatsächlich eine Eigenschaft von a ist, so muß sie besonders geschützt sein.

                  Siehe auch </archiv/2007/10/t159610/>
                  Sie ist als DontEnum, DontDelete festgelegt.

                  Man kann sie ja zum Beipiel nicht mit einem String überschreiben.

                  Kann man schon versuchen. Wird aber ignoriert werden, weil der String keine sinnvolle Zahl ergibt:
                  http://bclary.com/2004/11/07/ecma-262.html#a-15.4.5.1

                  »»

                  Ja, also geschützt.

                  Lokale Variablen hängen an einem internen »lokale Variablen«-Objekt, auf das man aber nicht direkt zugreifen kann. arguments ist eine solche »lokale Variable«.

                  Ein Objekt für alle Funktionen?

                  Nein, jeder Function-Scope hat sein eigenes arguments-Objekt, siehe Link im letzten Posting.

                  Wenn das gar nicht standardisiert ist, kann man eigentlich keine Aussagen darüber machen. In JScript, nur als Beispiel, könnte es ja ganz anders sein.

                  Sind die lokalen Variablen dann nur temporär (persistente Eigenschaften würden den Speicher zumüllen).

                  Natürlich, solange ein Scope noch irgendwo »konserviert« ist (Stichwort Closures), existieren die lokalen Variablen, ansonsten werden sie sofort aus dem Speicher geräumt.

                  Ich meine nicht, wie der Zugriff eines JS-Skripts geregelt ist, das ist klar. Und ich vermute auch, die belegten Speicherbereiche werden freigegeben. Aber es könnte dennoch ein Singletonobjekt oder ähnliches geben, wo alle lokalen Variablen drin landen. Weil JS nicht standardisiert ist usw. ...

                  »arguments« ist ja kein wirklich unabhängig vom Scope existierendes Objekt, sondern nur eine Zugriffsweise.

                  Und das ist Teil meiner Fragen. Wird arguments temporär während der Ausführung einem Funktionsobjekt zugewiesen, gibt es temporär während der Ausführung ein unabhängiges "Ausführungsobjekt" oder werden lokale Variablen sonstwie gespeichert? Andererseits bliebe es jedem, der einen JS-Interpreter schreibt, selbst überlassen, wie er das macht, da es ja offensichtlich keinen Standard gibt.

                  in anderen Sprachen bedarf es dazu nicht solch verwirrender Unterscheidungen und "doppelter" Datentypen. In PHP werden seit Version 5 Objekte standardmäßig als Referenzen übergeben.

                  PHP ist kein Vergleich, weil es keine konsequent objektorientierte Sprache ist. Das Problem ergibt sich nur in solchen. Ein String ist in PHP kein Objekt, hat keine Methoden und kann auch keine Member vom Prototyp erben.

                  Das mag sein. Aber das klärt nicht, wieso es überhaupt auch für die skalaren Datentypen diese Objektverwirklichung gibt. Ich denke nicht, man kann C++ nicht als stark, wenn vielleicht auch nicht konsequent, objektorintiert bezeichnen. Dort gibt es eine klare Abgrenzung zwischen skalaren und höheren Datentypen.

                  Ich denke mal eher, Java, Ruby oder Python wären in dieser Hinsicht mit JavaScript vergleichbare Sprachen, mit denen kenne ich mich aber überhaupt nicht aus. (Tiiim!)

                  Java kenne ich auch zuwenig, die anderen gar nicht. Soweit ich weiß, ist dort ein String einfach nur ein String.

                  Ja, aber früher konnte man ja über funktionsname.lokaleVariable auf sie zugreifen.

                  Mit Sicherheit nicht.

                  Ich bin mir fast sicher ;) Mal mit einem alten Netscape ausprobieren!

                  Ich glaube mit arguments geht das immer noch.

                  Ja, aber Funktionsname.arguments war mal von Netscape JavaScript eingeführt und ist jetzt deprecated, in ECMAScript ist arguments eine lokale Variable.

                  Ich weiß. Aber was folgt daraus für ein Schluß? arguments existiert zweimal (einmal als temporäres Datum des "internen Objektes", einmal als Eigenschaft des eigentlichen Funktionsobjektes)? Und wie ist es bei length? Das wird ja nun wirklich nicht wie eine lokale Variable adressiert.

                  1. Hallo Mathias, zonk,

                    Primitive Werte »haben« genauso Methoden insofern, dass sie intern ständig in die entsprechenden Objekte »umgewandelt« werden.
                    Das hatte ich bei der Antwort von Tim anders verstanden (Stichworte: eigene toString()-Methoden, toPrimitive()).

                    Vielleicht hab ich mich da missverständlich ausgedrückt. ToPrimitive, ToString, ToBoolean sind Hilfs-Funktionen innerhalb des ECMAScript-Interpreters. Manchmal rufen diese bei Objekten deren tatsächlich in JS definierte Methoden auf. Bei primitiven Werten jedoch nicht.

                    Nein, jeder Function-Scope hat sein eigenes arguments-Objekt, siehe Link im letzten Posting.
                    Wenn das gar nicht standardisiert ist, kann man eigentlich keine Aussagen darüber machen. In JScript, nur als Beispiel, könnte es ja ganz anders sein.

                    Im ECMAScript-Standard ist genau definiert, dass diese nur ein einem eigenen Exekutionskontext existierten. Wie der jeweils lokale Stack genau umgesetzt ist, nicht. arguments existiert nur in diesem lokalen Scope.

                    Ich denke mal eher, Java, Ruby oder Python wären in dieser Hinsicht mit JavaScript vergleichbare Sprachen, mit denen kenne ich mich aber überhaupt nicht aus. (Tiiim!)

                    In Python ist alles ein Objekt. Früher gab es zwar eine Unterschied zwischen Types und Classes; das war aber vor meiner Zeit. Sprich damit definiert man ein Objekt:

                    >>> s = "eins zwei drei"

                    (Die „>>>“ hier kommen von der interaktiven Python Shell.)

                    Es ist vom Typ String ...

                    ~~~python

                    type(s)

                    <type 'str'>

                      
                    ... der gleichzeitig die Klasse für das Objekt bildet:  
                      
                      ~~~python
                    
                    >>> s.__class__  
                    
                      <type 'str'>
                    

                    Typen existieren immer noch, sind aber mit Klassen vereint. Hier macht sich jemand die Mühe, das auseinander zu dröseln, aber im wesentlich kann man sich sagen: „Alles ist ein Objekt“.

                    Als Objekt hat man immer Zugriff auf alle Eigenschaften, ob nun Properties oder Methoden:

                    ~~~python

                    dir(s)

                    ['add', 'class', 'contains', 'delattr', 'doc', 'eq',
                      'ge', 'getattribute', 'getitem', 'getnewargs', 'getslice',
                      'gt', 'hash', 'init', 'le', 'len', 'lt', 'mod',
                      'mul', 'ne', 'new', 'reduce', 'reduce_ex', 'repr',
                      'rmod', 'rmul', 'setattr', 'str', 'capitalize', 'center',
                      'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index',
                      'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper',
                      'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex',
                      'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines',
                      'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

                      
                    Ausdrücke wie Sting-Konkatenation wird intern auf die Methoden mit den komischen Unterstrichen des Objektes umgesetzt:  
                      
                      ~~~python
                    
                    >>> s + " vier"  
                    
                      'eins zwei drei vier'  
                      >>> s.__add__(" vier")  
                      'eins zwei drei vier'
                    

                    Sprich: Objekte sind selbst für die Implementierung von Operatoren zuständig und können diese damit überladen.

                    In Ruby ist es ähnlich. Objekt:

                    ~~~ruby s = "eins zwei drei"
                      s.class        # Ergibt 'String'

                      
                    Sämtliche Methoden:  
                      
                      ~~~ruby
                    "bla".methods  
                      [method, send, %, rindex, between?, reject, []=, split, <<, object_id, strip,  
                      size, singleton_methods, downcase, gsub!, count, succ!, __send__, downcase!,  
                      intern, member?, squeeze!, equal?, taint, *, next, find, frozen?,  
                      instance_variable_get, each_with_index, rstrip!, each_line, +, kind_of?, sub,  
                      slice!, instance_eval, to_a, tr, replace, collect, reverse, all?, type,  
                      unpack, entries, lstrip, protected_methods, capitalize, chop!, extend,  
                      capitalize!, scan, to_sym, detect, eql?, display, instance_variable_set, zip,  
                      each_byte, is_a?, casecmp, hash, gsub, empty?, to_str, map, to_s, tr_s, any?,  
                      tr!, class, match, sort, rstrip, tainted?, private_methods, next!, swapcase,  
                      min, chomp!, swapcase!, ljust, untaint, find_all, upto, hex, each, sum, id,  
                      reverse!, chop, to_i, insert, <, inject, <=>, inspect, delete, dump, ==,  
                      tr_s!, >, concat, ===, clone, succ, sort_by, public_methods, strip!, max,  
                      rjust, >=, respond_to?, freeze, index, select, <=, slice, oct, __id__, to_f,  
                      length, chomp, methods, upcase, partition, =~, sub!, squeeze, upcase!, crypt,  
                      delete!, nil?, dup, grep, instance_variables, lstrip!, include?, instance_of?,  
                      center, []]
                    

                    Darunter sind auch Methoden, die woanders Operatoren wären, also fast wie in Python. Nur sind die hier netter benannt. Dank Rubys Syntax sind das hier die gleichen Methoden-Aufrufe:

                    ~~~ruby "Romeo" + " & Julia"  # Ergibt 'Romeo & Julia'
                      "Julia".+(" & Romeo") # Ergibt 'Julia & Romeo'

                      
                    In Ruby sind Klassen nicht geschlossen, d.h. man kann wie in Javascript neue Methoden hinzufügen bzw. bereits definierte ersetzen:  
                      
                      ~~~ruby
                    class String  
                        def +(other)  
                          "Nix da!"  
                        end  
                      end  
                      
                      puts "Romeo" + " & " + "Julia"   # Ergibt 'Nix da!'
                    

                    Java kenne ich auch zuwenig, die anderen gar nicht. Soweit ich weiß, ist dort ein String einfach nur ein String.

                    Soweit ich weiss – mein Java-Wissen ist aber ewig her – arbeitet Java mit String  - (unveränderlich) bzw. StringBuffer-Objekten (veränderlich) realisiert, auch wenn im Quellcode Literale stehen. Die Verbindung mit „+“ ist dadurch realisiert, dass der +-Operator der einzige überladene Operator in Java ist, d.h. für Strings reagiert er anders als für Zahlen. Man möge mich korrigieren, wenn ich Unsinn rede.

                    (So ganz unter uns: Ich mag die dynamische Variante von Python und Ruby lieber.)

                    Tim

                    1. Hallo,

                      Hallo Mathias, zonk,

                      Primitive Werte »haben« genauso Methoden insofern, dass sie intern ständig in die entsprechenden Objekte »umgewandelt« werden.
                      Das hatte ich bei der Antwort von Tim anders verstanden (Stichworte: eigene toString()-Methoden, toPrimitive()).

                      Vielleicht hab ich mich da missverständlich ausgedrückt. ToPrimitive, ToString, ToBoolean sind Hilfs-Funktionen innerhalb des ECMAScript-Interpreters. Manchmal rufen diese bei Objekten deren tatsächlich in JS definierte Methoden auf. Bei primitiven Werten jedoch nicht.

                      Ja, so hatte ich es verstanden. Ich fasse das mal zusammen: Diese von Dir genannten Funktionen können durch eigene Funktionen "überschrieben" werden. Dabei werden sie nicht wirklich intern überschrieben, weil erstens der Interpreter ein kompiliertes Programm ist, was nicht mal eben von Skripten in Teilen geändert werden kann, und weil zweitens das bei manchen Methoden auch gar keinen Sinn machen würde. Wenn es möglich wäre, die interne valueOf()-Methode für (primitive) Zahlen zu überschreiben, würde sich der Datentyp selbst aufheben, der nun mal als acht Byte im Fließkommaformat gespeichert wird und nicht mal eben von einem Skript durch Änderung von valueOf() kurzerhand in einen String mit fatalen Folgen geändert werden kann. Number-Objekte nutzen die interne valueOf-Methode() primitiver Zahlen, solange sie nicht durch im Skript deklarierte valueOf-Methoden ersetzt werden, was dort problemlos möglich ist, weil nicht die komplette Funktionsfähigkeit des Interpreters dadurch außer Kraft gesetzt wird, wie es bei Änderungen an der valueOf()-Methode primitiver Datentypen der Fall wäre.

                      Ich habe daher die Vermutung, primitive Datenwerte werden bei der Verarbeitung nicht in entsprechende Objekte umgewandelt, sondern sie nutzen dieselben internen Routinen wie die Objekte. Für Objekte kann man sie durch eigene ersetzen (nicht überschreiben!), für primitive Datentypen nicht oder nur zum Teil. Wenn für ein Numberobjekt neue Methoden definiert werden, können primitive Zahlen darauf zugreifen, werden dabei aber nicht wirklich in Numberobjekte umgewandelt.

                      Nein, jeder Function-Scope hat sein eigenes arguments-Objekt, siehe Link im letzten Posting.
                      Wenn das gar nicht standardisiert ist, kann man eigentlich keine Aussagen darüber machen. In JScript, nur als Beispiel, könnte es ja ganz anders sein.

                      Im ECMAScript-Standard ist genau definiert, dass diese nur ein einem eigenen Exekutionskontext existierten. Wie der jeweils lokale Stack genau umgesetzt ist, nicht. arguments existiert nur in diesem lokalen Scope.

                      Also so wie meinte: Für Skripte ist die Sichtbarkeit standardisiert. Die lokalen Variablen existieren im Kontext einer Funktion, solange diese ausgeführt wird. Wie das intern gehandhabt wird (lokale Variablen existieren dauerhaft oder auch nicht, sie werden als Arrays, Objekte, in einem Heap oder sonstwie gespeichert, ist Sache des Interpreterentwicklers)?

  2. Hallo Zonk,

    Wieso wird bei a. o1 nicht mit toString in eine Zeichenkette umgewandelt, in b. aber schon? alert("30" + 30) wandelt doch auch 30 in die Zeichenkette "30" mit dem Ergebnis 3030 um.

    Die Krux liegt darin, wie der Ausdruck ausgewertet wird, daraus folgt die Typumwandlung.

    alert("Das Objekt " + o1);
    "Das Objekt 1"

    Hier befinden wir uns in einem Additions-Ausdruck. Dieser ist im ECMAScript-Standard so definiert (Kommentare von mir):

    The production AdditiveExpression : AdditiveExpression +
      MultiplicativeExpression is evaluated as follows:

    Produktion heisst hier soviel wie „Muster im Quelltext“. Lass Dich nicht von „MultiplicativeExpression“ irritieren, das kann auch einzelne Objekte identifizieren.

    1. Evaluate AdditiveExpression.
      2. Call GetValue(Result(1)).
      3. Evaluate MultiplicativeExpression.
      4. Call GetValue(Result(3)).

    Das dient nur dazu, die Ausdrücke rekursiv auf einzelne Werte zusammenzudampfen und mit der ECMAScript-internen (also nicht nach aussen sichtbaren) Funktion GetValue() das tatsächliche Objekt bzw den tatsächlichen Wert statt nur einer Referenz auf diesen zu bekommen.

    5. Call ToPrimitive(Result(2)).
      6. Call ToPrimitive(Result(4)).

    Das wird hier gleich wichtig.

    7. If Type(Result(5)) is String or Type(Result(6)) is String, go to step 12.

    Hier werden, wenn nur einer der beiden Werte vom Typ String ist, die gesamten Zahlenadditionsschritte übersprungen. Mache ich auch mal.

    ...
      12. Call ToString(Result(5)).
      13. Call ToString(Result(6)).
      14. Concatenate Result(12) followed by Result(13).
      15. Return Result(14).

    Hier werden die Strings noch mal explizit in String-Primitives umgewandelt (klingt absurd, ich weiss), zusammengehängt und zurückgegeben.

    Wichtig ist noch diese Notiz:

    NOTE
      No hint is provided in the calls to ToPrimitive in steps 5 and 6.

    Wofür ist dieser Aufruf der wiederum internen Funktion ToPrimitive() notwendig? Der Additionsoperator will explizit mit richtigen Werten arbeiten – ToPrimitive ist also dazu zuständig etwaige Objekte in primitive Werte umzuwandeln. Es ist im wesentlichen  als Tabelle spezifiziert, normale Werte bleiben gleich, nur für Objekte kriegen einen leicht kompliziertere Behandlung:

    Object – Return a default value for the Object. The default value of an object
      is retrieved by calling the internal [[DefaultValue]] method of the object,
      passing the optional hint PreferredType. The behaviour of the [[DefaultValue]]
      method is defined by this specification for all native ECMAScript objects.

    Neben internen Funktionen haben Objekte auch noch interne Methoden. [[DefaultValue]] ist dazu zuständig einen konkreten Wert zu kreieren. Entweder als String mit toString() oder als „Wert“mit valueOf(). Zusätzlich kriegt diese interne Methode noch ein optionales Argument PreferredType als Vorschlag übergeben, mögliche Werte sind String und Number. ToPrimitive kriegt diesen möglichen Hint auch übergeben und gibt den auch weiter. Die nervige Schritt-für-Schritt-Beschreibung mal zusammengefasst:

    • Wenn der Hint „String“ ist:
      1. Versuch toString() aufzurufen. Wenn das einen primitiven Wert zurückgibt,
         gib diesen zurück.
      2. Versuch valueOf() aufzurufen. Wenn das einen primitiven Wert zurückgibt,
         gib diesen zurück.
      3. Gib auf und werfe einen TypeError.

    • Wenn der Hint „Number“ ist:
      1. Versuch valueOf() aufzurufen. Wenn das einen primitiven Wert zurückgibt,
         gib diesen zurück.
      2. Versuch toString() aufzurufen. Wenn das einen primitiven Wert zurückgibt,
         gib diesen zurück.
      3. Gib auf und werfe einen TypeError.

    Und was ist, wenn kein Hint da ist?

    When the [[DefaultValue]] method of O is called with no hint, then it behaves
      as if the hint were Number, unless O is a Date object (see 15.9), in which
      case it behaves as if the hint were String.

    In unserem Fall sieht die interne Abfolge also so aus:

    1. "Objekt " + o1 ruft intern ToPrimitive(o1) auf.
    2. Das ruft o1.[[DefaultValue]] auf.
    3. Dieses gibt den Wert von o1.valueOf() zurück - Dein "1"-String.

    Warum setzt der Additionsausdruck keinen Hint? Vermutlich, weil er für beides, Addition und Stringkonkatention zuständig ist.

    Warum ist der Hint „Number“ default? Ich habe keine Ahnung. Ich vermute höchstens, dass toString() zu speziell für die meisten Anwendungen von ToPrimitive ist.

    b. alert(o1);
    b. Wie ich denke "o"

    Was passiert dagegen hier? alert() ist nicht von ECMAScript spezifiziert, deswegen kann ich nur raten. Allerdings ist es offensichtlich, dass alert() den enthaltenen Ausdruck in einen String umwandeln muss. Dazu verwendet es wohl die interne Funktion ToString und hier wird für Objekte als Argument als Hint beim Aufruf von ToPrimitive explizit der Hint String gesetzt:

    Apply the following steps:
      1. Call ToPrimitive(input argument, hint String).
      2. Call ToString(Result(1)).
      3. Return Result(2).

    In einem expliziten String-Kontext wird also durchaus toString() aufgerufen.

    c. alert(o1 + o1);
    c. Ich erwarte 2: trifft zu.

    Hm? In welchem Browser hast Du getestet? In Spidermonkey, dem Mozilla-JS-Interpreter, kriege ich als Ausgabe "11" wie es auch die Spezifikation vermuten lässt. Oder hast Du oben einen Tippfehler gemacht und Dein o.prototype.valueOf() soll gar keinen String ("1") zurückgeben, sondern eine Zahl (1)?

    Tim

    1. Hallo Gunnar,

      Wieso wird bei a. o1 nicht mit toString in eine Zeichenkette umgewandelt, in b. aber schon? alert("30" + 30) wandelt doch auch 30 in die Zeichenkette "30" mit dem Ergebnis 3030 um.

      Das wollte ich noch beantworten. Der Wert 30 wird beim Aufrufen der internen Funktion ToPrimitive direkt ohne Umwandlung als primitive Zahl zurückgegeben, weil er vom Typ number ist. Weil der primitive Wert "30" aber vom Typ string ist springt man in der Auswertung des Additionsausdrucks aber zu Schritt Zwölf ...

      12. Call ToString(Result(5)).
        13. Call ToString(Result(6)).

      ... in dem noch mal explizit alles zu Strings umgewandelt wird.

      Tim

    2. Hallo Tim,

      vielen Dank für Deine ausführliche Antwort. Ich habe mir Deinen Post durchgelesen und werde mir das auch mal sichern und Deinen Links nachgehen.

      Ich habe jetzt einige neue Fragen zu Deiner Antwort.

      Die Krux liegt darin, wie der Ausdruck ausgewertet wird, daraus folgt die Typumwandlung.

      Genau das ist mein Problem:)

      alert("Das Objekt " + o1);
      "Das Objekt 1"

      Hier befinden wir uns in einem Additions-Ausdruck.

      Ist hier mit Additionsausdruck sowohl eine numerische Addition als auch Konkatenation gemeint?

      Egal, was mir nicht einleuchtet, ist, wie der Interpreter bei unterschiedlichen Datentypen vorgeht. Logisch (jedenfalls für mich) wäre es, wenn es eine einheitliche Regel gäbe, wie verschiedene Datentypen verbunden werden. Bei skalaren Werten scheint das ja auch so zu sein

      x = "30" + 30;

      Wann immer eine Zeichenkette mit einer Zahl über diesen Operator verbunden wird, wird die Zahl zuvor in eine Zeichenkette umgewandelt.

      Hier werden, wenn nur einer der beiden Werte vom Typ String ist, die gesamten Zahlenadditionsschritte übersprungen. Mache ich auch mal.

      Das trifft ja bei "Das Objekt " + o1 zu.

      Neben internen Funktionen haben Objekte auch noch interne Methoden. [[DefaultValue]] ist dazu zuständig einen konkreten Wert zu kreieren. Entweder als String mit toString() oder als „Wert“mit valueOf(). Zusätzlich kriegt diese interne Methode noch ein optionales Argument PreferredType als Vorschlag übergeben, mögliche Werte sind String und Number. ToPrimitive kriegt diesen möglichen Hint auch übergeben und gibt den auch weiter. Die nervige Schritt-für-Schritt-Beschreibung mal zusammengefasst:

      Es ist also wegen toPrimitive nicht haltbar, wenn man sagt, primitive
      Werte würden bei der Benutzung temporär in entsprechende Objekte (String, Number, Boolean) umgewandelt?

      • Wenn der Hint „String“ ist:

      Woraus ergibt sich der Hint? Aus dem Kontext (Operatoren, bestimmter Datentyp, den eine Funktion verlangt)?

      Und was ist, wenn kein Hint da ist?

      »»

      Was könnte eine solche Situation auslösen?

      When the [[DefaultValue]] method of O is called with no hint, then it behaves
        as if the hint were Number, unless O is a Date object (see 15.9), in which
        case it behaves as if the hint were String.

      In unserem Fall sieht die interne Abfolge also so aus:

      1. "Objekt " + o1 ruft intern ToPrimitive(o1) auf.
      2. Das ruft o1.[[DefaultValue]] auf.
      3. Dieses gibt den Wert von o1.valueOf() zurück - Dein "1"-String.

      Warum setzt der Additionsausdruck keinen Hint? Vermutlich, weil er für beides, Addition und Stringkonkatention zuständig ist.

      »»

      Setzt er wirklich keinen Hint, oder ist der Hint vielleicht Number?

      Warum ist der Hint „Number“ default? Ich habe keine Ahnung. Ich vermute höchstens, dass toString() zu speziell für die meisten Anwendungen von ToPrimitive ist.

      Genau hier fehlt mit eine eindeutige Vorgehensweise.

      b. alert(o1);
      b. Wie ich denke "o"

      Was passiert dagegen hier? alert() ist nicht von ECMAScript spezifiziert, deswegen kann ich nur raten. Allerdings ist es offensichtlich, dass alert() den enthaltenen Ausdruck in einen String umwandeln muss.

      Ja. Soweit ich weiß, erwartet alert() auch selbst schon einen String, wobei ein anderer Wert notfalls umgewandelt wird.

      In einem expliziten String-Kontext wird also durchaus toString() aufgerufen.

      Und genau den würde ich für

      "Das Objekt " + o1

      erwarten.

      o1 + o1 ist hingegen nicht eindeutig (bzw. überhaupt nicht) als ein Stringkontext zu sehen. Deswegen wäre hier valueOf() korrekt.

      c. alert(o1 + o1);
      c. Ich erwarte 2: trifft zu.

      Hm? In welchem Browser hast Du getestet? In Spidermonkey, dem Mozilla-JS-Interpreter, kriege ich als Ausgabe "11" wie es auch die Spezifikation vermuten lässt. Oder hast Du oben einen Tippfehler gemacht und Dein o.prototype.valueOf() soll gar keinen String ("1") zurückgeben, sondern eine Zahl (1)?

      Du hast recht, war mein Fehler. Ich bitte um Entschuldigung. Richtig wäre return 1 gewesen.

      1. Hallo Ihr,

        Solche grundlegenden Zusammenhänge finde ich interessant. Nur so kann man letzlich das Biest JavaScript richtig durchschauen. Nach der Lektüre eurer Diskussion stellt sich bis jetzt für mich die Sache so dar:

        Es geht anscheinend darum, ob die toString-Methode oder die valueOf-Methode zum Zug kommt, wenn ein Objekt bzw. ein Primitve-Ausdruck ausgewertet wird.

        Im Unterschied zu einem Primitive kann ein Objekt (eigene) Eigenschaften und Methoden haben. Wenn nun ein Objekt o1 z.B. mit
        alert(o1);
        nur ausgegeben werden soll, erscheint es völlig logisch, dass die Auswertung mit der toString-Methode des Objekts geschieht, denn man hat ja nicht angegeben, dass man eine bestimmte Eigenschaft/Methode des Objekts meint, geschweige denn welche.

        Dieses Verhalten passt analog zu dem Umstand, dass existierende Objekte bei ähnlich einfachen Auswertungen wie
        if(o1){...}
        immer true ergeben. Es ist mir natürlich klar, dass bei if(o1){...} nicht die toString-Methode im Spiel ist.

          
        function o(){} o1 = new o();  
        alert(o1); // [object Object]  
        alert( String(o1)===o1.toString() ); // true  
        alert( String(o1.valueOf())===o1.toString() ); // true  
          
        o.prototype.toString = function (){return 1;};  
        alert(o1); // 1  
        alert( Number(o1) ); // 1  
        alert( Number(o1.valueOf())===o1.toString() ); // true  
          
        o.prototype.valueOf = function (){return 2;};  
        alert(o1); // 1  
        alert( Number(o1) ); // 2  
        alert( Number(o1.valueOf())===o1.toString() ); // false  
        
        

        String() und Number() liefern entsprechende Primitives.
        Wie man sieht, greift die eingebaute valueOf-Methode auf toString zu.
        Sobald die valueOf-Methode aber überschrieben ist, wird diese auch ausschließlich benutzt, es sei denn, man will wirklich nur das Objekt selber mit alert() ausgeben, dann wirkt trotzdem wieder toString().

        alert("Das Objekt " + o1);
        "Das Objekt 1"

        Hier befinden wir uns in einem Additions-Ausdruck.

        Ist hier mit Additionsausdruck sowohl eine numerische Addition als auch Konkatenation gemeint?

        Scheint so. Wenn immer eine weitere Auswertung stattfinden soll, wie eine Addition oder Konkatenation, dann ist es auch logisch, dass man eine bestimmte Eigenschaft/Methode des Objekts meint, seinen eigentlichen Wert, den dann eben valueOf() liefert:

          
        function o(){}  
        o.prototype.toString = function() { return "o"; };  
        o.prototype.valueOf = function() { return 1; };  
        o1 = new o();  
        alert("Das Objekt " + o1); // "Das Objekt 1"  
        alert(o1);                 // "o"  
        alert(o1 + o1);            // 2  
        
        

        Gruß, Don P

        1. Hallo,

          Scheint so. Wenn immer eine weitere Auswertung stattfinden soll, wie eine Addition oder Konkatenation, dann ist es auch logisch, dass man eine bestimmte Eigenschaft/Methode des Objekts meint, seinen eigentlichen Wert, den dann eben valueOf() liefert:

          Nein, das finde ich gar nicht logisch:

          z = new Number (5);
          Number.prototype.toString = function() {
          return "fünf";
          };

          alert(z); // fünf
          alert(z+5); // 10
          alert(z+ " Kisten"); // 5 Kisten

          z2 = 5;

          alert(z2); // 5
          alert(z2+5); // 10
          alert(z2+ " Kisten"); // 5 Kisten

          Angenommen, die toString()-Methode würde für alle Zahlen eine verbale Umschreibung zurückgeben. Dann macht es imo keinen Sinn, wenn

          alert(z+ " Kisten")

          nicht "fünf Kästen" ausgibt.

          Noch ärgerlicher ist, wenn

          alert(z2); nicht "fünf", sondern 5 ausgibt, nur weil z2 primitiv deklariert wurde.

          1. Hallo zonk,

            Nein, das finde ich gar nicht logisch:

            z = new Number (5);
            Number.prototype.toString = function() {
            return "fünf";
            };

            alert(z); // fünf
            alert(z+5); // 10
            alert(z+ " Kisten"); // 5 Kisten

            z2 = 5;

            alert(z2); // 5
            alert(z2+5); // 10
            alert(z2+ " Kisten"); // 5 Kisten

            Ok, das scheint jetzt wieder relativ inkonsequent, hast recht.
            IMO hätte man von Anfang an den "+" Operator nicht mehrdeutig implementieren sollen, dann gäbe es auch nicht solche Probleme.

            Leider hatte JavaScript keine Zeit, sich von seinen Kinderkrankheiten zu erholen, weil es viel zu schnell überall verbreitet war, und nachträglich konnte bzw. wollte man an der Sprache selbst nicht mehr viel herumdoktern.

            Douglas Crockford, von dessen Kenntnissen ich sehr viel halte, empfiehlt, Primitives wo immer möglich zu verwenden und nicht die entsprechenden Objekte, auch gerade wegen solcher Ungereimtheiten.

            Es gibt es auch viele, die grundsätzlich davon abraten, die eingebauten Objekte zu erweitern bzw. deren Methoden zu überschreiben. Dafür gibt es ebenfalls gute Gründe. Man kann ja auch separate Objekte und Methoden für den gleichen Zweck schreiben.

            Don P

            1. Hallo,

              Ok, das scheint jetzt wieder relativ inkonsequent, hast recht.
              IMO hätte man von Anfang an den "+" Operator nicht mehrdeutig implementieren sollen, dann gäbe es auch nicht solche Probleme.

              Ja, das denke ich auch.

              Leider hatte JavaScript keine Zeit, sich von seinen Kinderkrankheiten zu erholen, weil es viel zu schnell überall verbreitet war, und nachträglich konnte bzw. wollte man an der Sprache selbst nicht mehr viel herumdoktern.

              »»

              Irgendwie geht es die letzten Jahre, seitdem Netscape weg ist, mit der Sprache sowieso nicht mehr vorwärts.

              1. Hallo,

                Irgendwie geht es die letzten Jahre, seitdem Netscape weg ist, mit der Sprache sowieso nicht mehr vorwärts.

                Naja, das kann ich nicht beurteilen, bin relativ neu im "richtigen" JavaScript. Zwar programmiere ich schon länger damit, aber eher so wie die meisten: Mal kurz die eine andere Syntax nachgeschlagen und mit ein bisschen Trial and Error die eine oder andere coole Funktion hingebastelt, fertig. Objektorientierung? Nada. Aber das ändert sich jetzt...

                Dass es vorwärts gehen könnte mit dem Sprachkern, d.h. z.B. eine Änderung am Verhalten des "+" Operators, kann man ohnehin vergessen. Es würde ja keines der Milliarden existierenden Scripte mehr laufen. Man müsste dazu eine neue Sprache etablieren.

                Die einzige Abhilfe ist wohl, sich solche "Fallen" bewusst zu machen (was wir ja hier tun), und dann einen Programmierstil zu entwickeln und zu pflegen, der diese umgeht, wie eben die grundsätzliche Vermeidung von String- Number- oder gar Boolean-Objekten.

                Gruß, Don P

                1. Dass es vorwärts gehen könnte mit dem Sprachkern, d.h. z.B. eine Änderung am Verhalten des "+" Operators, kann man ohnehin vergessen. Es würde ja keines der Milliarden existierenden Scripte mehr laufen. Man müsste dazu eine neue Sprache etablieren.

                  Dafür gibt es das Attribut language, das mittlerweile, warum auch immer, als deprecated erklärt wurde. Es gab in der Vergangenheit schon einige Änderungen am Sprachkern und -verhalten. Das ist also kein Argument. In HTML ist das nicht anders, da gibt es für alte Sachen den Quirks-Mode.

                  Die einzige Abhilfe ist wohl, sich solche "Fallen" bewusst zu machen (was wir ja hier tun), und dann einen Programmierstil zu entwickeln und zu pflegen, der diese umgeht, wie eben die grundsätzliche Vermeidung von String- Number- oder gar Boolean-Objekten.

                  Keine gute Idee. Etwas Schlechtes sollte man nicht mit schlechten Workarounds umgehen. Wenn Du zum Beispiel PHP zum Vergleich heranziehst, da gab es mit der fünften Version eine radikale Änderung beim Objekthandling, was inkompatibel mit alten Skripts ist. In Version 4 gab es etwas ähnliches mit Formularwerten, die nicht mehr als globale Variablen zur Verfügung stehen. Die Entwickler waren mutig genug, diese Schritte im Interesse konsistenter und sicherer Programmierung zu gehen.

                2. Hallo Ihr zwei,

                  Irgendwie geht es die letzten Jahre, seitdem Netscape weg ist, mit der Sprache sowieso nicht mehr vorwärts.

                  Äh. ECMAScript und damit auch Javascript wird seit über einem Jahr von der zuständigen Arbeitsgruppe rasant und stark weiterentwickelt; manche meinen sogar zu stark. Einzelne Bestandteile der Weiterentwicklung lassen sich in den derzeit noch proprietären Varianten Javascript1.6, 1.7 und 1.8 finden.

                  Für ECMAScript 4, auf dem JS 2.0 basieren wird sind durchaus größere Dinge geplant, ein Klassen-basiertes Objekt-System, Interfaces, Namensräume, Packages, optionales Typing, etc., etc. Und wenn sich das nicht wieder verändert hat, wird die Unterscheidung zwischen Primitives und Objekt-Wrappern aufgehoben.

                  Das dumme ist, dass das alles noch sehr stark im Flux ist und man sich die Informationen aus Präsentationen von JS-Erfinder und Mozilla-Guru Brendan Eich oder aus den stark disorganisierten EMCAScript-Wiki zusammen suchen muss.

                  Dass es vorwärts gehen könnte mit dem Sprachkern, d.h. z.B. eine Änderung am Verhalten des "+" Operators, kann man ohnehin vergessen.

                  Soweit ich das sehe, wird in ES4 eindeutig auf eingebaute Operatoren mit all ihren hier im Thread dokumentierten Schwächen verzichtet und stattdessen normale überladbare Methoden oder Funktionen nutzen. Da fliegen zwei Vorschläge rum, der eine würde Klassenmethoden der entsprechenden Klasse nutzen:

                  class MyString {
                        public static function +(left: MyString, right: MyString) : MyString {
                            return left.concat(right);
                        }
                    }

                  Der andere definiert generische Funktionen, also nicht an Objekte gebunden, die sich in ihrer Signatur (Typisierung) unterscheiden und dementsprechend angewandt werden:

                  generic function (a, b) {... };
                    generic function (a: Number, b: Number) : Number { ... };
                    generic function (a: String, b: String) : String { ... };

                  Wie das auch realisiert wird; mit beiden Varianten könnte man das derzeitige Verhalten des +-Operators nachbilden, um Abwärtskompabilität zumindest im Default zu erzeugen.

                  Tim

                  1. Hallo,

                    Irgendwie geht es die letzten Jahre, seitdem Netscape weg ist, mit der Sprache sowieso nicht mehr vorwärts.

                    Äh. ECMAScript und damit auch Javascript wird seit über einem Jahr von der zuständigen Arbeitsgruppe rasant und stark weiterentwickelt; manche meinen sogar zu stark.

                    Ich weiß. Was ich meinte, ist, wie lange ist es her, seit es die letzte offizielle Version gab?

                    Siehe Datum dieses Artikels: http://www.drweb.de/javascript/javascript2.shtml

                    Damals konnte ich V2 kaum erwarten. Und - ist jetzt Jahre her. Selbst wenn von Mozilla Dev. was Neues kommt, wie lange wird es dauern, bis es auch die anderen Hersteller in ihre Browser einbauen?

                    Für ECMAScript 4, auf dem JS 2.0 basieren wird sind durchaus größere Dinge geplant, ein Klassen-basiertes Objekt-System, Interfaces, Namensräume, Packages, optionales Typing, etc., etc. Und wenn sich das nicht wieder verändert hat, wird die Unterscheidung zwischen Primitives und Objekt-Wrappern aufgehoben.

                    Ja, endlich.