2009-06-25 14 views
7

Dopo aver letto un po 'sul Javascript del prototypical inheritance model, a cambiare il mio stile di costruire una classe damodo migliore per accedere ai membri privati ​​in Javascript

var Some_Class = function() { 
    this.public_method = function() { 
    }; 
    (function() { 
     // constructor 
    }).call(this) 
} 

a

var Some_Class = function() { 
    (function() { 
     // constructor 
    }).call(this) 
} 
Some_Class.prototype.public_method = function() { 
}; 

Anche se capisco che questo è un buona pratica, ma non sono più autorizzato ad accedere ai metodi privati ​​dal metodo pubblico

var Some_Class = function() { 
    var private_member = 'whatever'; 

    (function() { 
     // constructor 
    }).call(this) 
} 
Some_Class.prototype.public_method = function() { 
    return private_member; // not possible 
}; 

Dopo la lettura attraverso un articolo here (costruttore Chiusura-creato), poi sono uscito con questa

var Some_Class = function() { 
    var private_member = 'whatever', 

    private_method = function(_some_value) { 
     // private method implementation 
    }; 

    if(!arguments.callee.prototype.public_method) { 
     arguments.callee.prototype.public_method = function() { 
      private_method.call(this, private_method); 
     }; 
    } 

    (function() { 
     // constructor 
    }).call(this) 
} 

Tuttavia, quali sono gli svantaggi di fare questo ?! o c'è un modo migliore per farlo se voglio accedere a private member nel metodo pubblico?

risposta

10

L'uso di variabili e chiusure di scope di funzioni per simulare variabili/funzioni private è un idioma ben consolidato nella comunità javascript. Se la variabile è veramente intesa come privata, non vedo alcun inconveniente a questo approccio (anche se alcuni sostengono che il codice performante su alcuni browser/host debba prestare attenzione a quante chiusure vengono create).

Nell'esempio, private_method (e il relativo ambiente) sono condivisi tra tutti gli oggetti, poiché la chiusura public_method viene creata solo la prima volta che l'oggetto viene costruito (e associato alla proprietà prototype del costruttore che imposta il prototipo interno dell'oggetto creato) chain) - quindi il private_method che viene utilizzato è solo quello che è stato creato la prima volta.

Ecco alcuni esempi di codice che vi aiuterà a illustrare ciò che sta accadendo:

 
    var global = 1; 

    var Some_Class = function() { 
    var private_method = 'whatever'; 
    var now = ++global; 
    print("outer now: " + now); 
    private_method = function(_some_value) { 
     // private method implementation 
     print("inner now: " + now); 
    }; 

    if(!arguments.callee.prototype.public_method) { 
     arguments.callee.prototype.public_method = function() { 

      private_method.call(this, private_method); 
     }; 
    } 

    (function() { 
     // constructor 
    }).call(this) 
} 

new Some_Class().public_method(); // outer now: 2, inner now: 2 
new Some_Class().public_method(); // outer now: 3, inner now: 2 
new Some_Class().public_method(); // outer now: 4, inner now: 2 

Sei sicuro che è quello che vuoi?

Se il tuo private_method non ha bisogno di fare riferimento allo stato dell'oggetto che racchiude, quindi vedo poco beneficio nel fare le cose nel modo in cui stai facendo.

Cosa faccio di solito (se devo usare 'nuovo' per creare il mio oggetto) è la seguente:

 
function MyClass() { 
    var private_var = 1; 
    function private_func() 
    { 

    } 
    this.public_func = function() 
    { 
    // do something 
    private_func(); 
    } 
    this.public_var = 10; 
} 

var myObj = new MyClass(); 

Lo svantaggio di questo approccio è che ogni volta che si costruisce l'oggetto via 'nuovo' Ricreare tutte le chiusure. Ma a meno che il mio profiler non mi dica che questa scelta progettuale deve essere ottimizzata, preferisco la sua semplicità e chiarezza.

Inoltre non vedo il vantaggio nel codice di fare le seguenti due:

 
    (function() { }).call(this); // call the constructor 

Perché stai creando un ambito distinto nel costruttore?

+0

grazie per averlo chiarito, per la seconda domanda ... Immagino sia perché probabilmente non sono ancora molto familiare al modello di oggetti e voglio rendere il mio codice simile al codice OOP in php/java/other OOP linguaggio di programmazione – Jeffrey04

11

La mia risposta è una non risposta: non c'è l'accesso private integrato in JavaScript, ma va bene perché YAGNI. Ecco come faccio private membri nel mio codice:

function Some_Class() { 
    this._private_member = 'whatever'; 
} 

Some_Class.prototype._private_method = function() { 
}; 

Questo è abbastanza buono.Non vale davvero la pena di saltare attraverso i cerchi quando l'unico vero scopo di private è quello di proteggersi da ... te stesso.

(lo dico dopo aver trascorso molte ore io a giocare con ogni permutazione delle chiusure e prototipazione, così come sei, e, infine, dicendo "avvitare, non ne vale la pena".)

+0

Sono d'accordo. Forzare un falso accesso privato in lingue che non lo supportano di solito significa UR DOING IT RONG. – Triptych

+0

@Triptych - mentre di solito sono d'accordo sul fatto che se devi combattere un linguaggio ben progettato per fare ciò che vuoi fare, allora dovresti davvero riconsiderare il tuo design. Ma, in questo caso, la simulazione dell'accesso privato attraverso le variabili e le chiusure dell'oscuramento delle funzioni è riconosciuta come un idioma javascript naturale da parte di molti programmatori javascript ben consolidati e esperti. –

+0

+1 un effetto collaterale è che tutti gli stravaganti schemi di chiusura tendono a rompere molti IDE di assistenza al codice –

1

Se non l'hai Fatto questo, dai un'occhiata a questo JavaScript Module Pattern, che ti consente di accedere a metodi e variabili private all'interno delle funzioni pubbliche, ecc.

+0

: DI l'ho letto prima, solo che per qualche motivo non mi piace il modello singleton e voglio trovare un modo alternativo .. – Jeffrey04

0

Funziona con prototipo, non solo singleton. Il problema è che quando è il momento di sottoclasse, la mia sottoclasse non ha accesso ai privati ​​

+1

Anche le sottoclassi in Java non hanno accesso ai loro oggetti privati ​​'super'. – lcn

1

Echoing John Kugelman: È impossibile creare membri privati ​​in javascript. Convivici. Anche se si crea un contenitore come questo:

function SomeClass() { 

    var _private = 0; 
    this.public_acessor = function() {return _private}; 
} 

Qualsiasi utente può ancora scrivere:

SomeClass._not_private_anymore = 1; 
SomeClass.public_acessor = function() {return this._not_private_anymore}; 

Alla fine, non ci si può fidare qualsiasi membro del pubblico di essere lo stesso hai dichiarato. Se qualcuno ha intenzione di infrangere il tuo codice, lo farà! Un altro utente non romperà il tuo codice solo perché è utile.

Problemi correlati