Paul H.: OOP: Objekt von Außerhalb mit Funktion bestücken und ausführen

Hi,

ich bin grade dabei eine Drag&Drop Funktion für meinen Online-Kalender zu proggen. Nun sollen Objekte einer Klasse variable Funktionen bereitstellen, die zunächst bei der Initialisierung durch eine externe Funktion bestückt werden und zu bestimmten Ereignissen von extern aufgerufen werden. Allerdings möglichst im Kontext des Objekts selbst.

function klasse()  
{  
  var private_variable1;  
  var private_variable2;  
  this.oeffentliche_variable1;  
  
  this.onmyevent = null;  
}  
  
var objekt1 = new klasse();  
objekt1.onmyevent = new function()  
{  
  ...arbeite mit private_variable1, private_variable2 und oeffentliche_variable1...  
}  
  
function irgendeinefunktion()  
{  
  objekt1.onmyevent();  
}

Ich denke das verdeutlicht die Problematik ganz gut. Ich möchte also bei der Initialisierung des Objekts bestimmen, was die onmyevent-Funktion genau macht. Allerdings soll diese dann bei ihrem Aufruf im Kontext des Objekts selbst aufgerufen werden, wodurch dieses in der Lage ist auf dessen privaten Variablen zuzugreifen.

Wie programmier ich sowas?

  1. Hallo,

    JavaScript hat keine echten Klassen und daher auch keine echten privaten Member. »Private Variablen« funktionieren über Closures, d.h. im Konstruktor verschachtelte Funktionen. Die Sichtbarkeit/Kapselung funktioniert hier rein aufgrund des lexikalischen Scopes.

    Wenn du von außen eine weitere Methode an das Objekt hängst, so hat diese Methode keinen Zugriff auf den Funktionsscope des Konstruktors, weil sie nicht darin verschachtelt ist. Was du vorhast wird sich also in dieser Weise nicht umsetzen lassen.

    Ich möchte also bei der Initialisierung des Objekts bestimmen, was die onmyevent-Funktion genau macht.

    Dann definiere sie von vornherein am Objekt und setze öffentliche Parameter zur Initialisierung.

    Oder nutze pseudo-private Eigenschaften, die z.B. mit _ beginnen aber ansonsten normale Eigenschaften des Instanzobjektes sind.

    Oder bau dir einen Mechanismus, wie du Methoden von außen hinzufügen kannst, welche dann die privaten Daten als Parameter übergeben bekommen. Zum Beispiel könntest du beim Aufruf des Konstruktors Funktionen übergeben. Allerdings werden diese keinen direkten Zugriff auf die privaten Daten haben, da sie lexikalisch nicht im Konstruktor notiert wurden.

    Es gibt noch viele weitere Möglichkeiten. Wie flexibel musst die Lösung sein?

    Letztlich bin ich nicht der Meinung, dass es sich hier konzeptionell um private Daten handelt. Schließlich fügst du von außen öffentliche Methoden hinzu. Dass diese nicht privilegiert sind, halte ich im OOP-Konzept für stimmig (jetzt abgesehen davon, dass es in JavaScript ohnehin nicht anders geht).

    Das Konzept der Trennung von öffentlichen und privaten Daten soll dem Programmierer helfen, wohlstrukturierte Implementierungen durch separation of concerns und gute Interfaces zu schreiben. In den wenigsten Sprachen ist dies eine effektive Kapselung. Siehe:
    Wozu Kapselung gut ist und wann sie nötig ist
    http://forum.de.selfhtml.org/archiv/2011/2/t203423/#m1376643

    Daher würde ich die Variablen einfach zu pseudo-privaten Eigenschaften machen. Du machst ohnehin kein streng klassenbasiertes OOP, sondern erzeugst Objekte durch prototypische Delegation und Komposition. Das ergibt in JavaScript völlig Sinn, beißt sich aber mit dem Konzept privater Member.

    Mathias

  2. Hallo,

    Ich denke das verdeutlicht die Problematik ganz gut. Ich möchte also bei der Initialisierung des Objekts bestimmen, was die onmyevent-Funktion genau macht. Allerdings soll diese dann bei ihrem Aufruf im Kontext des Objekts selbst aufgerufen werden, wodurch dieses in der Lage ist auf dessen privaten Variablen zuzugreifen.

    Wie programmier ich sowas?

    Vielleicht Crockfords "use functions to make functions"? Und auch das "new" vermeiden?

    http://jaoo.com.au/dl/jaoo-sydney-2009/slides/DouglasCrockford_WritingLargeApplicationsInJavaScript.pdf

    ungetestet:

      
    var objectMaker = function () {  
        var _myPrivate = "bla";  
        return {  
            objMethod : function () {  
                alert(_myPrivate);  
           }  
        }  
    }  
    var myObj1 = objectMaker();  
    myObj1.objMethod();  
    
    

    Ansonsten: jQuery oder irgendein anderes Framework verwenden (mootoos, YUI, ...)

    Gruß

    jobo

  3. Hallo,
    Theoretisch müsste auch dieser Ansatz gehen:

    function klasse(onMyEvent)  
    {  
      var private_variable1;  
      var private_variable2;  
      this.oeffentliche_variable1;  
      
      this.onmyevent = function () {onMyEvent(private_variabel1,  
      private_variable2);}  
      
    }  
      
    }
    

    Oder auch über einen Getter:

    function klasse()  
    {  
      var private_variable1;  
      var private_variable2;  
      this.oeffentliche_variable1;  
      
      this.onmyevent = null;  
      this.getPrivateVariable1 = function () {return(private_variable1);};  
      
    }  
      
    ...  
    obj1.onmyevent = function () {  
       doSomethingWith (this.getPrivateVariable1());  
    }  
      
    }
    

    Damit konservierst Du gewissermassen die benötigten Daten, sprich die
    Variablen "private_variable1" und "private_variable2" sowie die "onMyEvent"-Methode bleiben auf dem Stack, auch wenn der Konstruktor verlassen wird (Stichwort Closure).

    Ob das allerdings so elegant an dieser Stelle ist weiß ich nicht....ich würde wohl eher mit öffentlichen Variablen arbeiten (this.private_variable1 =...), und mir diese entsprechend als "private" kennzeichen (durch ein "_"-Präfix o.ä., wie schon in anderen Posts vorgeschlagen), denn das "private"-Konzept in JavaScript ist ohnehin kein "echtes" (wie in Javva/C# o.ä.)

    Hope that helps,

    Jörg

    1. Hallo,

      Ob das allerdings so elegant an dieser Stelle ist weiß ich nicht....ich würde wohl eher mit öffentlichen Variablen arbeiten (this.private_variable1 =...), und mir diese entsprechend als "private" kennzeichen (durch ein "_"-Präfix o.ä., wie schon in anderen Posts vorgeschlagen), denn das "private"-Konzept in JavaScript ist ohnehin kein "echtes" (wie in Javva/C# o.ä.)

      Privat bleibt privat. Bei Closures kommst du nicht an die Variable heran von außen. Es ist eben nicht klassenbasiert sondern funktional. Das Konzept ist das selbe, die Umsetzung einen andere.

      Gruß

      jobo