T-Rex: Von Instanz direkt auf Eigenschaft zugreifen

Hallo,

Hab da eine Klasse gebaut, welche unter anderem die Eigenschaft obj besitzt. Diese Eigenschaft wird Außerhalb der Klasse ziemlich oft gebraucht. Ich muss ständig mit .obj drauf zugreifen.

function Klasse()
{
   this.obj = "was auch immer"
}

var Instanz = new Klasse;
alert(Instanz.obj); -> ausgabe "was auch immer";

Ich würde das ganze gerne umprogrammieren, damit ich ohne den Zusatz .obj auf die Eigenschaft zugreifen kann. Sprich eine Weiterleitung in der Klasse.
alert(Instanz); -> ausgabe "was auch immer";

Gruß
T-Rex

  1. Hi,

    var Instanz = new Klasse;
    alert(Instanz.obj); -> ausgabe "was auch immer";

    Ich würde das ganze gerne umprogrammieren, damit ich ohne den Zusatz .obj auf die Eigenschaft zugreifen kann. Sprich eine Weiterleitung in der Klasse.
    alert(Instanz); -> ausgabe "was auch immer";

    Das sollte machbar sein, wenn du dem Objekt eine eigene toString-Methode spendierst, die den Inhalt von obj zurueckgibt.

    Den Wert darueber auch zu setzen, duerfte allerdings nicht moeglich sein - aber das wuerde das OO-Prinzip ja dann auch eher pervertieren, wenn du im Code ein Objekt ueberschreibst, um effektiv lediglich eine Eigenschaft von diesem zu aendern.

    MfG ChrisB

    --
    „This is the author's opinion, not necessarily that of Starbucks.“
    1. Den Wert darueber auch zu setzen, duerfte allerdings nicht moeglich sein - aber das wuerde das OO-Prinzip ja dann auch eher pervertieren, wenn du im Code ein Objekt ueberschreibst, um effektiv lediglich eine Eigenschaft von diesem zu aendern.

      In C++ kann man den Zuweisungsoperator überladen, mir wird das immer als tolles Feature verkauft.

      --
      Reden ist Silber, Schweigen ist Gold, meine Ausführungen sind Platin.
      Self-Code: sh:( ch:? rl:( br:> n4:( ie:{ mo:) va:) de:> zu:} fl:| ss:| ls:~ js:|
    2. Hi Chris,

      den Wert setzen will ich ja nicht. Dennoch hab ich das mit dem toString Methode nciht ganz verstanden?!.
      Kannst du da vielleicht bitte ein Beispiel geben? Wäre echt Klasse.

      Danke
      T-Rex

      1. Hi,

        den Wert setzen will ich ja nicht. Dennoch hab ich das mit dem toString Methode nciht ganz verstanden?!.
        Kannst du da vielleicht bitte ein Beispiel geben?

        Wenn du ein JavaScript-Objekt in einem String-Kontext verwendest (also es bspw. per alert ausgeben laesst), welches aber nicht vom Typ String ist - dann muss ja irgendwie festgelegt werden, wie die Ausgabe dann lauten soll.

        Dafuer haben solche Objekte eine toString-Methode, die implizit aufgerufen wird, wenn du das Objekt in einem Kontext benutzt, wo nur ein String gebraucht werden kann.

        alert(document.body) beispielsweise wird dir "[object HTMLBodyElement]" (oder sowas aehnliches, je nach Browser - meine Beispielausgaben sind vom Opera) ausgeben. Es handelt sich also um ein Element vom Typ HTMLBodyElement - das laesst sich nicht direkt in einem Stringkontext "ausgeben", also liefert dessen toString-Methode eben jenen Text stattdessen.
        alert(document.body.toString()) liefert das gleiche - das waere der direkte Aufruf. Bei der obigen Schreibweise wird die Methode auch aufgerufen, nur eben implizit.

        Wenn wir mal dein Objekt aus deinem Eingangsposting nehmen,

        function Klasse() {  
          this.obj = "was auch immer"  
        }  
          
        var Instanz = new Klasse;  
        alert(Instanz.obj);
        
        • da gibt uns der alert nur [object Object] aus; aus dem Grund, dass dein Objekt sich nicht als String darstellen laesst. Nach einer toString-Methode wurde dabei gesucht; dein Objekt hatte aber keine eigene, also wurde die des generellen Object-Typs von JavaScript aufgerufen, von dem dein Objekt sie geerbt hat - und das gibt ein Objekt eben nur als "Object" aus.

        Wenn du jetzt aber deinem Objekt eine eigene Methode mit dem speziellen Namen toString verpasst - dann wird diese aufgerufen, sobald das Objekt irgendwo in einen Stringkontext ueberfuehrt werden muss. Und damit hast du die Kontrolle darueber, wie diese Ausgabe dann lautet - also kannst du sie bspw. auch den Wert der Objekt-Eigenschaft obj zurueckgeben lassen:

        function Klasse() {  
          this.obj = "was auch immer";  
          
          this.toString = function() {  
            return this.obj;  
          };  
        }  
          
        var instance = new Klasse();  
        alert(instance);
        

        (Diese Methode muss natuerlich "public" sein, also mit dem Keyword this deklariert werden, denn sie muss ja von ausserhalb des Objektes aufrufbar sein.)

        MfG ChrisB

        --
        „This is the author's opinion, not necessarily that of Starbucks.“
        1. Hi Chris,

          vielen Dank für deine ausführliche Beschreibung. Leider funktioniert es bei mir nicht, da this.obj ein Object ist (denk ich).
          function Klasse() {
            this.obj = document.getElementById('Knoten');

          this.toString = function() {
              return this.obj;
            };
          }

          var instance = new Klasse();
          alert(instance); <-- gibt einfach nix zurück

          das alert gibt einfach nix aus. Weder true noch false.
          Dementsprechend kann ich mit instance.offsetWidth (z.B.) auch nicht auf den Knoten zugreifen :(.

          Gruß
          T-Rex

          1. Hi,

            vielen Dank für deine ausführliche Beschreibung. Leider funktioniert es bei mir nicht, da this.obj ein Object ist (denk ich).
            function Klasse() {
              this.obj = document.getElementById('Knoten');

            Ja, das waere dann wieder ein HTMLElementObject - die JavaScript-Objektrepraesentation eines Knotens im DOM des HTM-Dokumentes.

            this.toString = function() {
                return this.obj;
              };
            }

            var instance = new Klasse();
            alert(instance); <-- gibt einfach nix zurück

            Das da "gar nichts" als Ausgabe kommt, haette ich zwar nicht erwartet - aber es ist vielleicht auch nicht verwunderlich.
            Na dem impliziten Aufruf einer toString-Methode erwartet der JS-Interpreter wohl, dass er jetzt auch einen String vorliegen haben muesste, der sich ausgeben liesse - das ist aber nicht der Fall, weil deine toString-Methode keinen String geliefert hat, sondern wiederum ein Object. Jetzt noch mal dessen toString-Methode aufzurufen, sollte zwar wieder [object HTMLElementObject] (o.ae.) bringen - aber diesen impliziten Aufruf macht der Interpreter jetzt wohl nicht mehr, weil er ja annimmt, er muesse bereits einen String vorliegen haben.

            Dementsprechend kann ich mit instance.offsetWidth (z.B.) auch nicht auf den Knoten zugreifen :(.

            Das kann sowieso nicht funktionieren.
            Hier liegt kein Kontext vor, in dem es notwendig waere, instance in einen String umzuwandeln - also wuerde auch eine toString-Methode des Objektes gar nicht erst aufgerufen.
            Damit greifst du also lediglich auf eine Eigenschaft offsetWidth der Instanz von "Klasse" zu, die diese aber nicht besitzt - das kann also hoechstens undefined ergeben.

            Irgendwie habe ich immer noch den Eindruck, dass du die Objektorientierung hier zu pervertieren versuchst.

            Wenn dein Element instance in einer Eigenschaft die Referenz auf ein weiteres Objekt gespeichert hat - dann nutze auch diese Eigenschaft zum Zugriff auf das Objekt, und ggf. zu ihm gehoerige weitere Eigenschaften.

            Warum versuchst du hier auf Teufel komm raus irgendwelche "Shortcuts" einzufuehren - die der gaengigen Vorgehensweise in der OO absolut widersprechen?

            MfG ChrisB

            --
            „This is the author's opinion, not necessarily that of Starbucks.“
          2. »[HTMLElement]e mit zusätzlichem Verhalten ausstatten«

            oder

            »Funktoren als Vehicle für abstrakte Datentypen in JavaScript«

            hallo again T-Rex,

            wenn Du die direkte referenzierung von [HTMLElement]en beibehalten,
            ihnen aber trotzdem zusaetzliches verhalten mit auf den weg geben
            willst, solltest Du genau dies mit deinem code abbilden.

            Du moechtest keinen zu instanziierenden wrapper schreiben, sondern
            die spezialisierung eines abstrakten datentyps - nennen wir die
            benoetigte implementierung eines solchen konstrukts einfach mal
            »Behavior« oder »Interface« oder eben auch »Trait«.

            aus der sicht von JavaScript handelt es sich bei der loesung um
            eine funktion, die wie ein konstruktor aufgebaut ist, aber nicht
            als solcher ueber den »new« operator aufgerufen wird.

            solche funktionen - wir geben ihnen mal den konzeptionellen namen
            »Funktor« bzw. »Functor« - werden immer im kontext schon vorhandener
            objekte ausgefuehrt und bereichern diese objekte dann um die im
            funktor vereinbarte prozesslogik und/oder datenstruktur.

            ein moeglicher beispielhafter loesungsansatz für Dein problem sieht
            dann so aus und verlangt wie immer der ueberpreufung in der [jconsole]:

            //  [document.getCurrentStyle]    - [http://www.pseliger.de/jsExtendedApi/jsApi.document.getCurrentStyle.dev.js]  
            document.getCurrentStyle = (function (nodeObj/*[HTMLElement|Node]*/, cssScheme/*[string|String](css-attributes written according to html-css-scheme)*/) {var isElementNode=(function(obj){return(obj&&(typeof obj.nodeName==="string")&&(typeof obj.nodeType==="number")&&(obj.nodeType===1));});var notDefined;var regXHyphenSepatator=(/\-(\w)/g);var replaceWithUppercase=(function(str,$1){return $1.toUpperCase();});var convertHtmlIntoJsCssScheme=(function(cssScheme){cssScheme=cssScheme.replace(regXHyphenSepatator,replaceWithUppercase);return(((cssScheme=="float")||(cssScheme=="cssFloat"))?("styleFloat"):(cssScheme));});var fct=(function(){return notDefined;});if(document.defaultView&&document.defaultView.getComputedStyle){fct=(function(nodeObj,cssScheme){var currStyle;if(isElementNode(nodeObj)){cssScheme=String(cssScheme);cssScheme=(((cssScheme=="cssFloat")||(cssScheme=="styleFloat"))?("float"):(cssScheme));currStyle=document.defaultView.getComputedStyle(nodeObj,"").getPropertyValue(cssScheme);}return((currStyle==="")?(notDefined):(currStyle));});}else if(document.documentElement&&document.documentElement.currentStyle){fct=(function(nodeObj,cssScheme){var currStyle;if(isElementNode(nodeObj)){currStyle=nodeObj.currentStyle[convertHtmlIntoJsCssScheme(String(cssScheme))];}return currStyle;});}return fct;})();  
              
            //  [document.getElmPosAbsolute]  - [http://www.pseliger.de/jsExtendedApi/jsApi.bundles.DOM.getters.dev.js]  
            document.getElmPosAbsolute = (function (elm) {var x=0,y=0;if(elm&&elm.offsetParent){x=elm.offsetLeft;y=elm.offsetTop;elm=elm.offsetParent;while(elm){x=x+elm.offsetLeft;y=y+elm.offsetTop;elm=elm.offsetParent;}}return{"left":x,"top":y};});  
              
              
            var HTMLElementBehavior = (function () { // der funktor [[HTMLElementBehavior]]  
              
              
              this.getCurrentStyle = (function (cssScheme) {  
              
                return document.getCurrentStyle(this, cssScheme);  
              });  
              this.getPosAbsolute = (function () {  
              
                return document.getElmPosAbsolute(this);  
              });  
            });  
              
              
            var obj = document.getElementsByTagName("div")["output"];  
              
              
            HTMLElementBehavior.call(obj); // [obj] das neue verhalten *beibringen*.  
              
              
            print("obj.getCurrentStyle(\"background-color\") : " + obj.getCurrentStyle("background-color"));  
            print("obj.getPosAbsolute().left : " + obj.getPosAbsolute().left);  
            print("obj.getPosAbsolute().top : " + obj.getPosAbsolute().top);
            

            links die zur am heutigen tag ausformulierten erkenntnis fuehrten:

            so long - peterS. - pseliger@gmx.net

            --
            »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
            Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
            ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
  2. gruss T - Rex,

    ...
    Ich würde das ganze gerne umprogrammieren, damit ich ohne den Zusatz
    .obj auf die Eigenschaft zugreifen kann. ...
    alert(Instanz); -> ausgabe "was auch immer";
    ...

    folgende machbarkeitsstudie mal bitte mit *copy und paste*
    der [jconsole] zukommen lassen.

    var MyOwnTypesConstructor = (function (typesValue) {  
      
     this.valueOf = (function () {  
      
      return typesValue;  
     });  
     this.toString = (function () {  
      
      return String(typesValue);  
     });  
    });  
      
      
    var myOwnType = new MyOwnTypesConstructor(23);  
      
    print("\n");  
    print("myOwnType + 19 : " + (myOwnType + 19)); // 42  
    print("myOwnType + \"19\" : " + (myOwnType + "19")); // "2319"  
    print("\n");  
    print("myOwnType : " + myOwnType); // 23  
    print("\n");  
    print("(typeof myOwnType) : " + (typeof myOwnType)); // "object"  
    print("(typeof (myOwnType + 0)) : " + (typeof (myOwnType + 0))); // "number"  
    print("(typeof (myOwnType + \"\")) : " + (typeof (myOwnType + ""))); // "string"
    

    weiterfuehrende links zu dieser thematik:

    so long - peterS. - pseliger@gmx.net

    --
    »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
    Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
    ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
    1. [code lang=javascript]var MyOwnTypesConstructor = (function (typesValue) {

      this.valueOf = (function () {

      return typesValue;
      });
      this.toString = (function () {

      return String(typesValue);
      });
      });[/quote]

      Hat aber auch Nachteile:

      [code lang=javascript]var o1=new MyOwnTypesConstructor(0);
      var o2=new MyOwnTypesConstructor(0);

      print("o1==o2: "+(o1==o2)); // false
      print("o1==0:  "+(o1==0)); // true
      print("o2==0:  "+(o2==0)); // true[/quote]

      D.h., die Regel "Wenn a gleich b und b gleich c, ist a gleich c" ist verletzt.

      --
      Reden ist Silber, Schweigen ist Gold, meine Ausführungen sind Platin.
      Self-Code: sh:( ch:? rl:( br:> n4:( ie:{ mo:) va:) de:> zu:} fl:| ss:| ls:~ js:|
      1. gruss Timo,

        Hat aber auch Nachteile:
        ...
        D.h., die Regel "Wenn a gleich b und b gleich c, ist a gleich c" ist verletzt.
        ...

        keineswegs ...

        var MyOwnTypesConstructor = (function (typesValue) {  
          
         this.valueOf = (function () {  
          
          return typesValue;  
         });  
         this.toString = (function () {  
          
          return String(typesValue);  
         });  
        });  
          
        var o1 = new MyOwnTypesConstructor(0);  
        var o2 = new MyOwnTypesConstructor(0);  
          
        print("o1 == o2: " + (o1 == o2)); // false  
        print("o1 == 0 : " + (o1 == 0));  // true  
        print("o2 == 0 : " + (o2 == 0));  // true  
          
        /*  
          
        
        > var o1=new MyOwnTypesConstructor(0);  
        > var o2=new MyOwnTypesConstructor(0);  
        >   
        > print("o1==o2: "+(o1==o2)); // false  
        > print("o1==0:  "+(o1==0)); // true  
        > print("o2==0:  "+(o2==0)); // true  
        >   
        > D.h., die Regel "Wenn a gleich b und b gleich c, ist a gleich c" ist verletzt.  
          
          
          ja und? - dass ergebnis ist keineswegs ueberraschend.  
          
          es werden auch keinerlei regeln verletzt; schliesslich  
          arbeiten wir hier mit objekten und nicht mit primitiven  
          typen bzw. werten.  
          
          die beim vergleichen zum tragen kommende automatische  
          typwandlung arbeitet JavaScript-regelkonform - siehe auch:  
        */  
          
        print("(o1 === o2) ? " + (o1 === o2)); // false  
        print("(o1 === 0)  ? " + (o1 === 0));  // false  
        print("(o2 === 0)  ? " + (o2 === 0));  // false  
          
        var num1 = new Number(0);  
        var num2 = new Number(0);  
          
        print("(num1 == num2) ? " + (num1 == num2)); // false ... objektreferenzen  
        print("(num1 == 0)    ? " + (num1 == 0));    // true  ... typwandlung durch wert  
        print("(num2 == 0)    ? " + (num2 == 0));    // true  ... typwandlung durch wert  
          
        print("(num1 === num2) ? " + (num1 === num2)); // false ... objektreferenzen  
        print("(num1 === 0)    ? " + (num1 === 0));    // false ... typwandlung ausgeschlossen  
        print("(num2 === 0)    ? " + (num2 === 0));    // false ... typwandlung ausgeschlossen
        

        mein fazit:

        bei der dem OP aufgezeigten loesung handelt es sich um eine
        nach ECMA 262 mustergueltige implementierung eigener objekttypen.

        so long - peterS. - pseliger@gmx.net

        --
        »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
        Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
        ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]