2010-02-18 5 views
12

Ich bin ein ziemlich Neuling in Javascript, und ich verbringe einige Zeit versuchen, namespaced Objekte in js zu erstellen. JetztGeschachtelte Klasse in Javascript, Vererbung von privaten Methoden

, das ist, was ich zu tun habe versucht:

MainObject = function() { 

    var privateVariable = "i'm private"; 

    var privateMethod = function() { 
     // doSomething 
    } 

    this.publicMethod = function() { 
     // doPublicSomething 
    } 
} 

MainObject.prototype.nested = function() { 

    this.publicNestedMethod = function() { 

     // that's not working at all 
     this.privateMethod(privateVariable); 

    } 
} 

MyObject = new MainObject(); 

MyObject.publicMethod(); 
MyObject.publicNestedMethod(); 

ich die geschachtelte Klasse innerhalb des ersten gehören versucht, aber es funktioniert nicht auch wenn ich versuche:

this.nested = function() { 

    var mainObject = this; 

    return { 
     publicNestedMethod = function() { 
      mainObject.privateMethod();    
     } 
    } 
}(); 

Jemand kann mir bitte helfen? Ich werde meine Meinung darüber verlieren.

Phaedra.

Antwort

14

Verschlüsse sind ein lexikalisches Merkmal, kein semantisches. Wenn das Objekt außerhalb des lexikalischen Bereichs eines anderen Objekts liegt, kann es nicht mehr "verschachtelt" werden und auf die lokalen Variablen des ersten Objekts zugreifen. Im Code Ihrer verschachtelten Funktion/Klasse gibt es keine this.privateMethod, da niemals ist, die eine Eigenschaft von MainObject sind. Es ist einfach eine lokale Variable innerhalb einer Funktion.

Es gibt keine Dinge wie "private Eigenschaften", "private Methoden" oder "private Mitglieder" in JavaScript. Verdammt, es gibt keine "Klasse". Einige Leute mögen es, private Mitglieder mit lokalen Variablen wie oben zu emulieren, aber dies führt zu Fällen wie diesem, wo die Diskrepanz zwischen den beiden Konzepten kommt und einen in den Hintern beißt.

Zusammenfassend ist es eine schlechte Idee, Java-Code mit all seinen OO-Techniken in JS zu schreiben, genauso wie es eine schlechte Idee ist, C-Code mit all seinen Zeigern und unbeschränkten Puffern in C# zu schreiben. Sicher, in beiden Fällen können Sie es tun, aber Sie würden die Merkmale der Sprache auf diese Weise nicht schätzen und ausnutzen.

Und jetzt, wo ich mit der Tirade fertig bin, können Sie etwas tun, um Funktionen „Namensraum“ zu erhalten: eine vernünftige Art und Weise ist zu

MainObject = function() { 
    var privateVariable = "I'm private"; 

    var privateMethod = function() { 
     alert('Private'); 
    } 

    this.publicMethod = function() { 
     alert('Public'); 
    } 

    this.nested = { 
     publicNestedMethod: function() { 
     privateMethod(); 
     } 
    }; 

    // or 

    this.nested = (function() { 
     var nestedPrivate = 5; 

     return { 
     publicNestedMethod: function() { 
      alert(nestedPrivate); 
      privateMethod(); 
     } 
     }; 
    })(); 
} 

MyObject = new MainObject(); 

MyObject.publicMethod(); 
MyObject.nested.publicNestedMethod();​ 
+0

was, wenn: this.nested = function() { var privateNested = function() { } return { } }(); – Phaedra

+0

Sie müssen Klammern um die Funktion hinzufügen (Deklaration vs. Ausdruck, siehe http://yura.thinkweb2.com/named-function-expressions/). Abgesehen davon ist es genau das, was eine Schließung ist - Sie kapseln lokale Variablen, die zum Zeitpunkt der Funktionserstellung verwendet werden. Bearbeitete die Antwort, um ein Beispiel zu zeigen. –

+0

Also das ist, wonach ich gesucht habe, denke ich. oder nicht? Mir fehlte die Parethesis. – Phaedra

0

Mit welchem ​​OO-System können Sie private Methoden erben? Ein Teil davon, privat zu sein, ist von anderen Objekten nicht zu erreichen.

In JS insbesondere "private Mitglieder" sind wirklich nur lokale Variablen der Funktion, wo sie deklariert werden. JS hat keine typischen OO-Vorstellungen von "class", "vererbung", "public" und "private", so dass Sie nicht erwarten können, Ihre OOP-Techniken wörtlich aus anderen OOP-Sprachen zu kopieren.

+0

In Java, wenn Sie eine innere Cass erstellen, können Sie auf die Hauptklasse private Methoden zugreifen, bin ich mir ziemlich sicher. Prototyping des verschachtelten Objekts, ich füge es der Hauptobjektinstanz hinzu. Also habe ich erwartet, dass es wie eine Schließung funktioniert, die mir Zugriff auf die Variablen des Hauptobjekts gibt. – Phaedra

+0

Denken Sie daran, dass JavaScript nur dem Namen nach Java ist. Sie sind so unterschiedlich, dass Sie in JS nichts erwarten können, was genauso funktioniert wie in Java. Da JS selbst keine Klassen hat, hat es auch keine inneren Klassen. – Gabe

6

Mit der Konvention des Strichs für „private“ Methoden Halte die Dinge organisiert.

MainObject = function() { 

     this._privateVariable = "i'm private"; 

     this._privateMethod = function() { 
      // doSomething 
     } 

     this.publicMethod = function() { 
      // doPublicSomething 
     } 
} 
0

Es ist eine Konvention. Sie können OO-Java-Techniken wie private Mitglieder imitieren, aber das ist nicht zu empfehlen. Sie können auf diese Weise nachahmen:

MyFunction = function(options){ 
    var private = {}; 
    //to reference MyFunction as a context 
    var that = this; 

    function privateFunctionThatCallPublicMethod(){ 
     that.publicFunction("hello"); 
    } 

    this.publicFunction = function(params){ 
     alert(params + " " + private); 
    } 
    ... 
} 

var instance = new MyFunction({oneOption:'fsdfsad'}); 

Dies ist die Bestzeiten Ansatz, den ich gefunden OO Java-Techniken zu emulieren ...

Aber es gibt ein Problem, ist sehr ineffizient ... Sie müssen verwenden Prototyp stattdessen, weil sonst ein Objekt pro Funktion pro Instanz der "Klasse" erstellt würde.

MyFunction = function(options){ 
    this._private = {}; 
} 

MyFunction.prototype._privateFunctionThatCallPublicMethod = function(){ 
    this.publicFunction("hello"); 
} 

MyFunction.prototype.publicFunction = function(params){ 
    alert(params + " " + this._private); 
} 

Wie denken Sie private Mitglieder sind (auf diese Weise) eine Konvention. Außerdem gibt es eine andere Sache, die Sie wissen müssen ...

Wenn Sie eine Funktion eines Objekts als Parameter an eine andere Funktion übergeben Sie den Kontext der Funktion binden muss ...

function bind(fnThis, fn) { 
    return function(){ 
    return fn.apply(fnThis, arguments); 
    }; 
} 

function makeSomething(callback){ 
    callback("hello"); 
} 

var instance = new MyFunction(); 
makeSomething(bind(instance, instance.publicFunction)); 

Dies liegt daran, dass Sie "this" als Instanz im body der publicFunction binden müssen, sonst wird stattdessen "window" verwendet.

4

Nun den Vorteil der prototypische Vererbung zur Verfügung zu stellen, wo alle „Unterklassen“ eine einzige Instanz des Verfahrens in Prototyp teilen, aber das Merkmal der Vererbungs private Instanzen bieten auch ... ich kam mit:

function Person(name,latentPower){ 
    var privatesForChildren = { password:"xyz" 
           ,latentPower:"invisibility"} 
    this.inherit = function(){ 
     for(v in privatesForChildren){ 
      eval("var " + v + "=privatesForChildren['" + v + "'];"); 
     } 
    } 
    this.name = name; 
    this.revealName = function(){ alert("My name is" + this.name + "."); } 
    this.revealPowers = function(){ alert("I'm normal."); } 
}  
function Mutant(name,latentPower,fuel){ 
    this.inherit.call(this); // Inherit private instance variables 
    var fuel = fuel; 
    this.name = name; 
    this.revealPowers = function(){ 
    alert("I manifest the powers of " + latentPower + " when I " + fuel + "."); 
    } 
} 
Mutant.prototype = new Person; 
Mutant.prototype.constructor = Mutant; 

bob = new Person("Bob","telekenesis"); 
jim = new Mutant("Jim","nausea","eat pizza"); 
buford = new Mutant("Buford","Teflon Man","breathe"); 

jim.revealName(); //Inherited properly from prototype 
bob.revealPowers(); 
jim.revealPowers(); 
buford.revealPowers(); //distinct from Jim's so is an "instance var" 
alert(bob.latentPower); //returns undefined 
alert(buford.latentPower); //returns undefined, so is "private". 

Wie nützlich ist das?