Ci sono degli svantaggi nell'usare una "classe" JavaScript con questo modello?JavaScript "classes"
risposta
Quello che stai facendo nel tuo esempio non è il modello di "classe" che le persone pensano di JS - in genere le persone pensano al modello di classe più "normale" di Java/C#/C++/etc che può essere simulato con le librerie.
Invece il vostro esempio è in realtà abbastanza normale e buon design JS, ma per completezza parlerò differenze di comportamento si vedrete tra i "membri" private e pubbliche avete
var private = "a private variable";
this.public = "a public variable";
Accesso private
dall'interno una qualsiasi delle tue funzioni sarà molto più veloce dell'accesso a public
perché la posizione di private
può essere determinata ragionevolmente bene solo con una ricerca statica da parte del motore JS. I tentativi di accedere a public
richiedono una ricerca, i motori JS più moderni eseguono un certo grado di cache di ricerca, ma è ancora più costoso di un semplice accesso varizzato.
var privatefn = function() { ... };
this.publicfn = function() { ... };
Le stesse regole di ricerca si applicano a queste funzioni con la variabile sopra accede, l'unica vera differenza (nel tuo esempio) è che se le funzioni sono chiamati, dicono privatefn()
vs this.publicfn()
, privatefn
sarà sempre ottenere il mondiale oggetto per this
. Ma anche se qualcuno fa
f = foo.publicfn;
f();
Poi la chiamata a f
avranno l'oggetto globale come this
ma sarà in grado di modificare la variabile private
.
Il modo più normale di eseguire le funzioni pubbliche (che risolve la funzione pubblica indipendente che modifica il problema dei membri privati) è di inserire funzioni pubbliche sul prototipo, ad es.
Foo.prototype.publicfn = function() { ... }
che costringe funzioni pubbliche di non modificare le informazioni private - ci sono alcuni momenti in cui questo non è un'opzione, ma è buona pratica in quanto riduce anche l'uso della memoria un po ', prendere:
function Foo1() {
this.f = function(){ return "foo" };
}
vs
function Foo2() {
}
Foo2.prototype.f = function(){ return "foo" };
In Foo1
si dispone di una copia dell'oggetto funzioni per ogni istanza di Foo1
(non tutto l'Emory, solo l'oggetto, per esempio. new Foo1().f !== new Foo2().f
) mentre in Foo2
c'è solo un oggetto funzione singolo.
Questo è buono finora, ma c'è un altro livello di accesso che hai tralasciato.
this.publicfn
è davvero un metodo privilegiato in quanto ha accesso a membri e funzioni privati.
Per aggiungere metodi che sono pubblici, ma non privilegiato, modificare il prototipo come segue:
FooClass.prototype.reallypublicfn = function() { ... };
nota che questo metodo non ha accesso ai membri privati della FooClass ma è accessibile attraverso qualsiasi istanza di FooClass.
Un altro modo di realizzare questo sta tornando questi metodi dal costruttore
var FooClass = function()
{
var private = "a private variable";
this.public = "a public variable";
var privatefn = function() { ... };
this.publicfn = function() { ... };
return {
reallypublicfn: function() { ...}
}
};
var foo = new FooClass();
foo.public = "bar";
foo.publicfn();
In sostanza, questi metodi di dati nasconde aiuto, se effettuata secondo le tecniche tradizionali OOP. In generale, migliorare la protezione dei dati e l'incapsulamento nelle tue classi è una buona cosa. Garantire un accoppiamento basso rende molto più semplice cambiare le cose lungo la strada, quindi esporre pubblicamente il meno possibile è davvero a tuo vantaggio.
Vedere https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript per una panoramica semplice e http://www.crockford.com/javascript/private.html per i dettagli su come realizzare queste cose.
Lo svantaggio principale è che ti ritroverai con una copia di publicfn per ogni istanza di FooClass. Se sarete creare un sacco di oggetti FooClass, sarebbe più efficiente per scrittura
FooClass.prototype.publicfn = function() { ... };
nota che questi due modi di creare publicfn non sono equivalenti . uno è privilegiato e l'altro no –
Dipende dalle vostre esigenze e performance relativa. Javascript non è la lingua più sicura per i caratteri e non è molto forte per quanto riguarda la visibilità dei membri. Tradizionalmente puoi avere visibilità "privata", "pubblica privilegiata" e "pubblica" all'interno di un tipo Javascript.
È possibile dichiarare i membri privati e pubblici privilegiati con:
function FooClass()
{
var privateVar = 1;
function privateFn()
{
return privateVar; // etc...
}
this.publicVar = 2;
this.publicFn = function()
{
return privateFn();
}
}
questo esempio viene utilizzata una chiusura di funzione, che consiste in una dichiarazione di funzione che include i valori dal campo di applicazione in cui si definisce la funzione. Questo è accettabile quando la visibilità dei membri è necessaria ma può portare a un sovraccarico. L'interprete JavaScript non può riutilizzare le definizioni privateFn o publicFn per ogni istanza poiché si riferiscono a variabili o funzioni nell'ambito esterno. Di conseguenza ogni istanza di FooClass risulta in uno spazio di archiviazione aggiuntivo per privateFn e publicFn. Se il tipo viene utilizzato raramente o con moderazione, la penalità delle prestazioni è neglegabile. Se il tipo viene usato molto spesso nella pagina, o se la pagina è più di uno stile "AJAX" in cui la memoria non viene liberata frequentemente poiché la pagina non viene scaricata, la penalità può essere più visibile.
Un approccio alternativo consiste nell'utilizzare i membri del prototipo. Questi sono membri pubblici non protetti. Dal momento che Javascript non è completamente sicuro per il tipo ed è relativamente facile da modificare dopo il caricamento, digitare la sicurezza e la visibilità dei membri non sono così affidabili per controllare l'accesso ai tipi interni. Per motivi di prestazioni, alcuni framework come Ajax di ASP.NET utilizzano invece la denominazione dei membri per inferire le regole di visibilità. Ad esempio, lo stesso tipo in ASP.NET Ajax potrebbe sembrare:
function FooClass2()
{
this._privateVar = 1;
this.publicVar = 2;
}
FooClass2.prototype =
{
_privateFn : function()
{
return this._privateVar;
},
publicFn : function()
{
return this._privateFn();
}
}
FooClass2.registerClass("FooClass2");
In questo caso i membri privati di ambito sono privati solo di nome, il prefisso "_" è considerata la seguente una variabile membro privata. Ha il rovescio della medaglia di impedire al membro di essere veramente privato, ma il vantaggio di consentire l'applicazione di patch in memoria dell'oggetto. L'altro vantaggio principale è che tutte le funzioni vengono create una volta dall'interprete e dal motore e riutilizzate più e più volte per il tipo. La parola chiave "this" quindi fa riferimento all'istanza del tipo anche se il riferimento alla funzione stessa è lo stesso.
Un modo di vedere la differenza in azione è quello di provare questo con entrambi i tipi (se non si dispone di ASP.NET Ajax, è possibile ignorare l'ultima riga FooClass2 che chiama registerClass())
var fooA = new FooClass(), fooB = new FooClass();
alert(fooA.publicFn===fooB.publicFn); // false
var foo2A = new FooClass2(), foo2B = new FooClass2();
alert(foo2A.publicFn===foo2B.publicFn); // true
Quindi è una questione di sicurezza del tipo e visibilità dei membri vs.prestazioni e la possibilità di patch in memoria
Inoltre, se posso menzionare qualcosa di utile a questo - Con prototype
è possibile aggiungere ulteriori metodi in seguito nel codice per estendere la funzione da un ambito esterno. Come un piccolo vantaggio, l'intero corpo con tutti i metodi non sarà reso ogni volta, quindi accelera le prestazioni di compilazione. Se hai già tutti i metodi dichiarati all'interno della funzione, questo richiederà più tempo per il rendering. Quindi, il mio consiglio, applicare questi ultimi solo quando diventano rilevanti nel codice corrente.
Esempio:
// inside
function fn(arg) {
this.val = arg;
fn.prototype.getVal =()=> {
console.log(this.val);
}
}
var func = new fn('value');
func.getVal();
// declare extern methods
function fn2(arg) {
this.val = arg;
}
fn2.prototype.getVal =()=> {
console.log(this.val);
}
var func2 = new fn2('value');
func2.getVal();
- 1. ES6 Classes Valore predefinito
- 2. HKEY_CURRENT_USER \ Software \ Wow6432Node \ Classes vs HKEY_CURRENT_USER \ Software \ Classes \ Wow6432Node
- 3. Ruby "Base" classes
- 4. protected Inner Classes
- 5. UnitTesting Static Classes
- 6. C# Array of Classes
- 7. Multiple classes in SVG
- 8. scale case classes domande
- 9. Unity Resolve Multiple Classes
- 10. Desigining Proper Classes
- 11. ReportDiagnostic on Partial Classes
- 12. py.test test parametrizing classes
- 13. Abstract Sealed Classes
- 14. Scala case classes in raccolte
- 15. Iterating through all JDK classes
- 16. C++ typename e inner classes
- 17. ASP.NET MVC V2 - Buddy Classes
- 18. java inner classes metodo accesso
- 19. Infinite Maven 'target/classes' folders
- 20. Che cos'è la directory "Classes-1.moved-aside" nella mia directory Classes?
- 21. Guice @Provides Methods vs Provider Classes
- 22. CSS Module, React e Overriding CSS Classes
- 23. Qual è l'operatore <= su Ruby Classes?
- 24. Clojure hot code swapping per uberjars/.classes
- 25. Haskell record syntax e type classes
- 26. Ruby on Rails: Modules vs. Classes
- 27. Thinging Checked Exceptions from Anonimo Inner Classes
- 28. Android Studio - ProGuard "java.io.IOException ... bin \ Classes (Nessun file o directory)"
- 29. Quali sono gli ostacoli per avere "cost classes" alla Scala?
- 30. Prevent Rails 2/3 dalla cache di Lib/Classes
Il vostro esempio FooClass non è corretto. La semantica del nuovo è effettivamente: "var foo = {}; foo .__ proto__ = FooClass.prototype; var temp = FooClass.call (temp); if (IsObject (temp)) foo = temp;". Questo significa che nel tuo esempio foo sarà il nuovo oggetto "{reallypublicfn: function() {...}}" quindi non avrà il prototipo FooClass o la funzione publicfn – olliej