2010-02-18 16 views
12

Sono piuttosto un newbie in javascript e sto passando un po 'di tempo a cercare di creare oggetti con nomi in js.Classe nidificata in javascript, ereditarietà dei metodi privati ​​

Ora, questo è quello che sto cercando di fare:

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(); 

ho cercato di includere la classe annidata all'interno del primo, ma non sta funzionando anche se provo:

this.nested = function() { 

    var mainObject = this; 

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

Qualcuno può aiutarmi per favore? mi perderò la testa.

Phaedra.

risposta

14

Le chiusure sono una caratteristica lessicale, non semantica. Se l'oggetto è al di fuori dell'ambito lessicale di un altro, non può più essere "annidato" e accedere alle variabili locali dell'ex. Nel codice della funzione/classe annidata, non esiste nulla come this.privateMethod, perché privateMethod è mai creato come proprietà di MainObject. È semplicemente una variabile locale all'interno di una funzione.

Non esistono cose come "proprietà private", "metodi privati" o "membri privati" in JavaScript. Diavolo, non esiste una "classe". Ad alcune persone piace emulare membri privati ​​usando le variabili locali come sopra, ma così facendo si verificano casi come questo, in cui la discrepanza tra i due concetti arriva e morde uno dietro.

Per concludere, è una cattiva idea scrivere codice Java, con tutte le sue tecniche OO in JS, così come è una cattiva idea scrivere codice C, con tutti i suoi puntatori e buffer illimitati, in C#. Certo, in entrambi i casi puoi farlo, ma non apprezzerai e sfrutteresti le caratteristiche del linguaggio in questo modo.

E ora che ho finito con lo sproloquio, si può fare qualcosa di simile per ottenere "namespace" funzioni:

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

cosa succede se: this.nested = function() {var privateNested = function() {} ritorno {} }(); – Phaedra

+0

È necessario aggiungere parentesi attorno alla funzione (dichiarazione vs espressione, vedere http://yura.thinkweb2.com/named-function-expressions/). Oltre a questo, è esattamente ciò che una chiusura è - stai incapsulando le variabili locali utilizzate al momento della creazione della funzione. Modificato la risposta per mostrare un esempio. –

+0

Quindi è quello che stavo cercando, penso. o no? mi mancava la parestesia .. – Phaedra

0

Quale sistema OO consente di ereditare metodi privati? Parte dell'essere privato è inaccessibile da altri oggetti.

In JS, in particolare, "membri privati" sono in realtà solo variabili locali della funzione in cui sono dichiarati. JS non ha le nozioni di OO tipiche di "classe", "ereditarietà", "pubblico" e "privato", quindi non ci si può aspettare di copiare le proprie tecniche OOP testualmente da altre lingue OOP.

+0

In java se si sta creando una cassina interna, è possibile accedere ai metodi privati ​​della classe principale, ne sono abbastanza sicuro. Prototipazione dell'oggetto nidificato, lo sto aggiungendo all'istanza dell'oggetto principale. Quindi mi aspettavo che funzionasse come una chiusura, permettendomi di accedere alle variabili dell'oggetto principale. – Phaedra

+0

Ricorda che JavaScript è come Java solo nel nome. Sono così diversi che non ci si può aspettare che qualcosa in JS funzioni come in Java. Dal momento che JS non ha classi di per sé, non ha nemmeno classi interne. – Gabe

6

utilizzando la convenzione di sottolineatura per i metodi "privati" è un modo ragionevole per mantieni le cose organizzate.

MainObject = function() { 

     this._privateVariable = "i'm private"; 

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

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

È una convenzione. Puoi imitare le tecniche OO Java come membri privati ​​ma non è raccomandato. Si può imitare in questo modo:

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'}); 

Questo è bests approccio che ho trovato di emulare le tecniche OO Java ...

Ma c'è un problema, è molto inefficiente ... è necessario utilizzare prototipo invece, perché altrimenti creerebbe un oggetto per funzione per istanza della "classe".

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

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

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

Come si pensa membri privati ​​sono (in questo modo) una convenzione. Inoltre, c'è un'altra cosa che dovete sapere ...

Quando si passa una funzione di un oggetto come un parametro a un'altra funzione è necessario associare il contesto della funzione di ...

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)); 

Questo perché è necessario associare "questo" come istanza nel corpo di publicFunction, altrimenti sarà invece "window".

4

bene per fornire il beneficio di ereditarietà prototipale in cui tutti i "sottoclassi" condividono una singola istanza del metodo in prototipo, ma per fornire anche la caratteristica di ereditare istanze private ... mi si avvicinò con:

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". 

Quanto è utile?

Problemi correlati