Qual è la differenza tra
var A = function () {
this.x = function () {
//do something
};
};
e
var A = function () { };
A.prototype.x = function () {
//do something
};
a1.x !== a2.x
; sul prototipo:a1.x === a2.x
Qual è la differenza tra
var A = function () {
this.x = function () {
//do something
};
};
e
var A = function () { };
A.prototype.x = function () {
//do something
};
a1.x !== a2.x
; sul prototipo:a1.x === a2.x
Risposte:
Gli esempi hanno esiti molto diversi.
Prima di esaminare le differenze, è necessario tenere presente quanto segue:
[[Prototype]]
proprietà privata dell'istanza .myObj.method()
), Questo all'interno del metodo fa riferimento all'oggetto. Laddove questo non sia impostato dalla chiamata o dall'uso di bind , per impostazione predefinita l'oggetto globale (finestra in un browser) o in modalità rigorosa rimane indefinito.Quindi, ecco i frammenti in questione:
var A = function () {
this.x = function () {
//do something
};
};
In questo caso, alla variabile A
viene assegnato un valore che è un riferimento a una funzione. Quando questa funzione viene chiamata utilizzando A()
, la funzione è questo non è impostato dalla chiamata in modo che il default è l'oggetto globale e l'espressione this.x
è efficace window.x
. Il risultato è che viene assegnato un riferimento all'espressione della funzione sul lato destro window.x
.
In caso di:
var A = function () { };
A.prototype.x = function () {
//do something
};
succede qualcosa di molto diverso. Nella prima riga, alla variabile A
viene assegnato un riferimento a una funzione. In JavaScript, tutti gli oggetti funzioni hanno una proprietà prototype per impostazione predefinita, quindi non esiste un codice separato per creare un oggetto A.prototype .
Nella seconda riga, ad A.prototype.x viene assegnato un riferimento a una funzione. Questo creerà una proprietà x se non esiste, o assegnerà un nuovo valore se lo fa. Quindi la differenza con il primo esempio in cui la proprietà x dell'oggetto è coinvolta nell'espressione.
Un altro esempio è di seguito. È simile al primo (e forse a cosa volevi chiedere):
var A = new function () {
this.x = function () {
//do something
};
};
In questo esempio, l' new
operatore è stato aggiunto prima dell'espressione della funzione in modo che la funzione venga chiamata come costruttore. Quando viene chiamato con new
, la funzione di questo è impostato per fare riferimento a un nuovo oggetto la cui privata [[Prototype]]
proprietà è impostata per fare riferimento pubblico del costruttore del prototipo . Pertanto, nell'istruzione di assegnazione, la x
proprietà verrà creata su questo nuovo oggetto. Quando viene chiamata come costruttore, una funzione restituisce questo oggetto per impostazione predefinita, quindi non è necessaria return this;
un'istruzione separata .
Per verificare che A abbia una proprietà x :
console.log(A.x) // function () {
// //do something
// };
Questo è un uso insolito di nuovo poiché l'unico modo per fare riferimento al costruttore è tramite A.constructor . Sarebbe molto più comune fare:
var A = function () {
this.x = function () {
//do something
};
};
var a = new A();
Un altro modo per ottenere un risultato simile è utilizzare un'espressione di funzione immediatamente invocata:
var A = (function () {
this.x = function () {
//do something
};
}());
In questo caso, A
assegnato il valore restituito di chiamare la funzione sul lato destro. Anche in questo caso, dal momento che questo non è impostato nella chiamata, sarà riferimento all'oggetto globale ed this.x
è efficace window.x
. Poiché la funzione non restituisce nulla, A
avrà un valore di undefined
.
Queste differenze tra i due approcci si manifestano anche se stai serializzando e deserializzando i tuoi oggetti Javascript su / da JSON. I metodi definiti sul prototipo di un oggetto non vengono serializzati quando si serializza l'oggetto, il che può essere utile quando ad esempio si desidera serializzare solo le porzioni di dati di un oggetto, ma non i suoi metodi:
var A = function () {
this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance));
// {"objectsOwnProperties":"are serialized"}
Domande correlate :
Sidenote: potrebbe non esserci un significativo risparmio di memoria tra i due approcci, tuttavia l'utilizzo del prototipo per condividere metodi e proprietà probabilmente utilizzerà meno memoria rispetto a ciascuna istanza con la propria copia.
JavaScript non è un linguaggio di basso livello. Potrebbe non essere molto utile pensare alla prototipazione o ad altri modelli di ereditarietà come un modo per cambiare esplicitamente il modo in cui viene allocata la memoria.
null
), ma questo è molto diverso dalla prototype
proprietà - che è sulle funzioni e su cui è impostato il prototipo di tutte le istanze quando sono costruite new
. Non posso credere che questo abbia ottenuto 87 voti positivi :-(
"The language is functional"
sei sicuro che questo sia ciò che significa funzionale?
A
una funzione, e l'altra metà riguarda i modi oscuri e non ortodossi di fare qualcosa di semplice.
Come altri hanno già detto nella prima versione, l'utilizzo di "this" comporta che ogni istanza della classe A abbia una propria copia indipendente del metodo di funzione "x". Considerando che l'uso di "prototipo" significherà che ogni istanza della classe A utilizzerà la stessa copia del metodo "x".
Ecco un po 'di codice per mostrare questa sottile differenza:
// x is a method assigned to the object using "this"
var A = function () {
this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
this.x = function() { alert( value ); }
};
var a1 = new A();
var a2 = new A();
a1.x(); // Displays 'A'
a2.x(); // Also displays 'A'
a1.updateX('Z');
a1.x(); // Displays 'Z'
a2.x(); // Still displays 'A'
// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };
B.prototype.updateX = function( value ) {
B.prototype.x = function() { alert( value ); }
}
var b1 = new B();
var b2 = new B();
b1.x(); // Displays 'B'
b2.x(); // Also displays 'B'
b1.updateX('Y');
b1.x(); // Displays 'Y'
b2.x(); // Also displays 'Y' because by using prototype we have changed it for all instances
Come altri hanno già detto, ci sono vari motivi per scegliere un metodo o l'altro. Il mio campione vuole solo dimostrare chiaramente la differenza.
this
dall'oggetto, che è il proprietario del metodo. cioè il metodo non ha alcun oggetto che ne sia il proprietario. In questo caso c'è un this
oggetto, come mostrato nella classe A nell'esempio.
Prendi questi 2 esempi:
var A = function() { this.hey = function() { alert('from A') } };
vs.
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
La maggior parte delle persone qui (in particolare le risposte più votate) hanno cercato di spiegare come sono diverse senza spiegare PERCHÉ. Penso che sia sbagliato e se capisci prima i fondamenti, la differenza diventerà evidente. Proviamo a spiegare prima i fondamenti ...
a) Una funzione è un oggetto in JavaScript. OGNI oggetto in JavaScript ottiene una proprietà interna (nel senso che non puoi accedervi come altre proprietà, tranne forse in browser come Chrome), spesso indicato come __proto__
(puoi effettivamente digitare anyObject.__proto__
Chrome per vedere a cosa fa riferimento. Questo è solo che , una proprietà, niente di più. Una proprietà in JavaScript = una variabile all'interno di un oggetto, niente di più. Cosa fanno le variabili? Indicano le cose.
Quindi a cosa __proto__
punta questa proprietà? Bene, di solito un altro oggetto (spiegheremo perché più avanti). L'unico modo per forzare JavaScript affinché la __proto__
proprietà NON punti a un altro oggetto è utilizzare var newObj = Object.create(null)
. Anche se lo fai, la __proto__
proprietà STILL esiste come proprietà dell'oggetto, ma non punta a un altro oggetto, ma punta a null
.
Ecco dove la maggior parte delle persone si confonde:
Quando crei una nuova funzione in JavaScript (che è anche un oggetto, ricordi?), Nel momento in cui viene definita, JavaScript crea automaticamente una nuova proprietà su quella funzione chiamata prototype
. Provalo:
var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined
A.prototype
è TOTALMENTE DIVERSO dalla __proto__
proprietà. Nel nostro esempio, "A" ora ha DUE proprietà chiamate "prototipo" e __proto__
. Questa è una grande confusione per le persone. prototype
e le __proto__
proprietà non sono in alcun modo correlate, sono cose separate che puntano a valori separati.
Potresti chiederti: perché JavaScript ha __proto__
proprietà create su ogni singolo oggetto? Bene, una parola: delegazione . Quando chiami una proprietà su un oggetto e l'oggetto non lo possiede, JavaScript cerca l'oggetto a cui fa riferimento __proto__
per vedere se lo possiede. Se non ce l'ha, guarda la __proto__
proprietà di quell'oggetto e così via ... fino a quando la catena non finisce. Da qui il nome catena prototipo . Ovviamente, se __proto__
non punta a un oggetto e invece punta a null
, buona fortuna, JavaScript lo capisce e ti restituirà undefined
per la proprietà.
Potresti anche chiederti, perché JavaScript crea una proprietà chiamata prototype
per una funzione quando la definisci? Perché cerca di ingannarti, sì ingannati che funzioni come linguaggi di classe.
Continuiamo con il nostro esempio e creiamo un "oggetto" da A
:
var a1 = new A();
C'è qualcosa che sta accadendo in background quando è successa questa cosa. a1
è una variabile ordinaria a cui è stato assegnato un nuovo oggetto vuoto.
Il fatto che tu abbia usato l'operatore new
prima di una chiamata di funzione ha A()
fatto qualcosa di AGGIUNTIVO in background. La new
parola chiave ha creato un nuovo oggetto che ora fa riferimento a1
e quell'oggetto è vuoto. Ecco cosa succede inoltre:
Abbiamo detto che su ogni definizione di funzione c'è una nuova proprietà creata chiamata prototype
(alla quale è possibile accedervi, diversamente dalla __proto__
proprietà) creata? Bene, quella proprietà è attualmente in uso.
Quindi ora siamo nel punto in cui abbiamo un a1
oggetto vuoto appena sfornato . Abbiamo detto che tutti gli oggetti in JavaScript hanno una __proto__
proprietà interna che punta a qualcosa ( a1
lo ha anche), sia esso nullo o un altro oggetto. Ciò che l' new
operatore fa è che imposta quella __proto__
proprietà in modo che punti alla prototype
proprietà della funzione . Leggi di nuovo. È fondamentalmente questo:
a1.__proto__ = A.prototype;
Abbiamo detto che A.prototype
non è altro che un oggetto vuoto (a meno che non lo cambiamo in qualcos'altro prima di definire a1
). Quindi ora sostanzialmente a1.__proto__
punta alla stessa cosa A.prototype
, che è quell'oggetto vuoto. Entrambi puntano allo stesso oggetto che è stato creato quando si è verificata questa linea:
A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}
Ora, sta succedendo un'altra cosa quando l' var a1 = new A()
elaborazione dell'istruzione. Fondamentalmente A()
viene eseguito e se A è qualcosa del genere:
var A = function() { this.hey = function() { alert('from A') } };
Tutta quella roba dentro function() { }
sta per essere eseguita. Quando raggiungi la this.hey..
linea, this
viene modificato in a1
e ottieni questo:
a1.hey = function() { alert('from A') }
Non tratterò perché this
cambiano, a1
ma questa è un'ottima risposta per saperne di più.
Quindi per riassumere, quando lo fai var a1 = new A()
ci sono 3 cose che accadono in background:
a1
.a1 = {}
a1.__proto__
viene assegnata la proprietà to point alla stessa cosa di A.prototype
points to (altro oggetto vuoto {})
La funzione A()
viene eseguita con this
set per il nuovo oggetto vuoto creato nel passaggio 1 (leggi la risposta a cui ho fatto riferimento in precedenza sul perché this
passa a a1
)
Ora proviamo a creare un altro oggetto:
var a2 = new A();
I punti 1,2,3 si ripeteranno. Noti qualcosa? La parola chiave è ripetere. Passaggio 1: a2
sarà un nuovo oggetto vuoto, passaggio 2: la sua __proto__
proprietà punterà alla stessa cosa A.prototype
e, cosa più importante, passaggio 3: la funzione A()
viene DI NUOVO eseguita, il che significa che a2
otterrà la hey
proprietà contenente una funzione. a1
e a2
hanno due proprietà SEPARATE chiamate hey
che indicano 2 funzioni SEPARATE! Ora abbiamo funzioni duplicate negli stessi due oggetti diversi che fanno la stessa cosa, oops ... Puoi immaginare le implicazioni di memoria di questo se abbiamo creato 1000 oggetti new A
, dopo che tutte le dichiarazioni di funzioni occupano più memoria di qualcosa come il numero 2. Quindi come possiamo impedirlo?
Ricorda perché la __proto__
proprietà esiste su ogni oggetto? In modo che se recuperi la yoMan
proprietà su a1
(che non esiste), __proto__
verrà consultata la sua proprietà, che se è un oggetto (e nella maggior parte dei casi lo è), controllerà se contiene yoMan
e, in caso contrario, consulterà l'oggetto __proto__
ecc. Se lo fa, prenderà quel valore di proprietà e te lo mostrerà.
Quindi qualcuno ha deciso di usare questo fatto + il fatto che quando crei a1
, la sua __proto__
proprietà punta allo stesso oggetto (vuoto) A.prototype
e fa questo:
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
Freddo! Ora, quando crei a1
, passa di nuovo attraverso tutti e 3 i passaggi precedenti e nel passaggio 3 non fa nulla, poiché function A()
non ha nulla da eseguire. E se lo facciamo:
a1.hey
Vedrà che a1
non contiene hey
e controllerà il suo __proto__
oggetto proprietà per vedere se ce l'ha, che è il caso.
Con questo approccio eliminiamo la parte dal passaggio 3 in cui le funzioni sono duplicate su ogni nuova creazione di oggetti. Invece di a1
e a2
avere un separato hey
proprietà, ora nessuno di loro ha. Il che, immagino, ormai hai capito te stesso. Questa è la cosa carina ... se capisci __proto__
e Function.prototype
, domande come queste saranno piuttosto ovvie.
NOTA: alcune persone tendono a non chiamare la proprietà Prototype interna in quanto __proto__
, ho usato questo nome attraverso il post per distinguerlo chiaramente dalla Functional.prototype
proprietà come due cose diverse.
__proto__
e .prototype
sono cose totalmente diverse.
Nella maggior parte dei casi sono essenzialmente gli stessi, ma la seconda versione consente di risparmiare memoria perché esiste solo un'istanza della funzione anziché una funzione separata per ciascun oggetto.
Un motivo per utilizzare il primo modulo è accedere ai "membri privati". Per esempio:
var A = function () {
var private_var = ...;
this.x = function () {
return private_var;
};
this.setX = function (new_x) {
private_var = new_x;
};
};
A causa delle regole di scoping di JavaScript, private_var è disponibile per la funzione assegnata a this.x, ma non al di fuori dell'oggetto.
Il primo esempio modifica l'interfaccia solo per quell'oggetto. Il secondo esempio cambia l'interfaccia per tutti gli oggetti di quella classe.
x
disponibile la funzione per tutti gli oggetti il cui prototipo è assegnato a una nuova istanza di A:function B () {}; B.prototype = new A(); var b = new B(); b.x() // Will call A.x if A is defined by first example;
Il problema finale con l'utilizzo this
invece di prototype
è che quando si sovrascrive un metodo, il costruttore della classe base farà ancora riferimento al metodo sovrascritto. Considera questo:
BaseClass = function() {
var text = null;
this.setText = function(value) {
text = value + " BaseClass!";
};
this.getText = function() {
return text;
};
this.setText("Hello"); // This always calls BaseClass.setText()
};
SubClass = function() {
// setText is not overridden yet,
// so the constructor calls the superclass' method
BaseClass.call(this);
// Keeping a reference to the superclass' method
var super_setText = this.setText;
// Overriding
this.setText = function(value) {
super_setText.call(this, "SubClass says: " + value);
};
};
SubClass.prototype = new BaseClass();
var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!
subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
contro:
BaseClass = function() {
this.setText("Hello"); // This calls the overridden method
};
BaseClass.prototype.setText = function(value) {
this.text = value + " BaseClass!";
};
BaseClass.prototype.getText = function() {
return this.text;
};
SubClass = function() {
// setText is already overridden, so this works as expected
BaseClass.call(this);
};
SubClass.prototype = new BaseClass();
SubClass.prototype.setText = function(value) {
BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};
var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
Se ritieni che questo non sia un problema, dipende dal fatto che puoi vivere senza variabili private e se hai esperienza sufficiente per conoscere una perdita quando ne vedi una. Inoltre, dover mettere la logica del costruttore dopo le definizioni del metodo è scomodo.
var A = function (param1) {
var privateVar = null; // Private variable
// Calling this.setPrivateVar(param1) here would be an error
this.setPrivateVar = function (value) {
privateVar = value;
console.log("setPrivateVar value set to: " + value);
// param1 is still here, possible memory leak
console.log("setPrivateVar has param1: " + param1);
};
// The constructor logic starts here possibly after
// many lines of code that define methods
this.setPrivateVar(param1); // This is valid
};
var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0
a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0
contro:
var A = function (param1) {
this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
this.publicVar = value; // No private variable
};
var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1
Ogni oggetto è collegato a un oggetto prototipo. Quando si tenta di accedere a una proprietà che non esiste, JavaScript cercherà l'oggetto prototipo dell'oggetto per quella proprietà e la restituirà se esiste.
La prototype
proprietà di un costruttore di funzioni si riferisce all'oggetto prototipo di tutte le istanze create con quella funzione durante l'utilizzo new
.
Nel tuo primo esempio, stai aggiungendo una proprietà x
a ciascuna istanza creata con la A
funzione.
var A = function () {
this.x = function () {
//do something
};
};
var a = new A(); // constructor function gets executed
// newly created object gets an 'x' property
// which is a function
a.x(); // and can be called like this
Nel secondo esempio si aggiunge una proprietà all'oggetto prototipo a cui A
puntano tutte le istanze create .
var A = function () { };
A.prototype.x = function () {
//do something
};
var a = new A(); // constructor function gets executed
// which does nothing in this example
a.x(); // you are trying to access the 'x' property of an instance of 'A'
// which does not exist
// so JavaScript looks for that property in the prototype object
// that was defined using the 'prototype' property of the constructor
In conclusione, nel primo esempio viene assegnata una copia della funzione a ciascuna istanza . Nel secondo esempio una singola copia della funzione è condivisa da tutte le istanze .
Qual è la differenza? => Molto.
Penso che la this
versione sia utilizzata per abilitare l'incapsulamento, ovvero nascondere i dati. Aiuta a manipolare le variabili private.
Diamo un'occhiata al seguente esempio:
var AdultPerson = function() {
var age;
this.setAge = function(val) {
// some housekeeping
age = val >= 18 && val;
};
this.getAge = function() {
return age;
};
this.isValid = function() {
return !!age;
};
};
Ora, la prototype
struttura può essere applicata come segue:
Adulti diversi hanno età diverse, ma tutti gli adulti hanno gli stessi diritti.
Quindi, lo aggiungiamo usando il prototipo, piuttosto che questo.
AdultPerson.prototype.getRights = function() {
// Should be valid
return this.isValid() && ['Booze', 'Drive'];
};
Vediamo ora l'implementazione.
var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )
var p2 = new AdultPerson;
p2.setAge(45);
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***
Spero che sia di aiuto.
Il prototipo è il modello della classe; che si applica a tutte le sue istanze future. Considerando che questa è l'istanza particolare dell'oggetto.
So che è stata data una risposta a morte, ma vorrei mostrare un esempio reale delle differenze di velocità.
Qui stiamo creando 2.000.000 di nuovi oggetti con un print
metodo in Chrome. Stiamo memorizzando ogni oggetto in un array. L'inserimento print
del prototipo richiede circa 1/2 del tempo.
Lascia che ti dia una risposta più completa che ho imparato durante un corso di formazione JavaScript.
La maggior parte delle risposte ha già menzionato la differenza, ovvero quando si prototipa la funzione è condivisa con tutte le (future) istanze. Considerando che la dichiarazione della funzione nella classe creerà una copia per ogni istanza.
In generale non c'è giusto o sbagliato, è più una questione di gusti o una decisione di progettazione a seconda delle esigenze. Il prototipo tuttavia è la tecnica che viene utilizzata per sviluppare in modo orientato agli oggetti, come spero che vedrai alla fine di questa risposta.
Hai mostrato due schemi nella tua domanda. Proverò a spiegarne altre due e cercherò di spiegare le differenze se rilevanti. Sentiti libero di modificare / estendere. In tutti gli esempi si tratta di un oggetto auto che ha una posizione e può muoversi.
Non sono sicuro che questo modello sia ancora rilevante al giorno d'oggi, ma esiste. Ed è bene saperlo. È sufficiente passare un oggetto e una proprietà alla funzione decoratore. Il decoratore restituisce l'oggetto con proprietà e metodo.
var carlike = function(obj, loc) {
obj.loc = loc;
obj.move = function() {
obj.loc++;
};
return obj;
};
var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();
Una funzione in JavaScript è un oggetto specializzato. Oltre ad essere invocata, una funzione può memorizzare proprietà come qualsiasi altro oggetto.
In questo caso Car
è una funzione ( pensa anche all'oggetto ) che può essere invocata come al solito. Ha una proprietà methods
(che è un oggetto con una move
funzione). Quando Car
viene invocata extend
, viene chiamata la funzione, che fa un po 'di magia, ed estende la Car
funzione (pensa all'oggetto) con i metodi definiti all'interno methods
.
Questo esempio, sebbene diverso, si avvicina di più al primo esempio nella domanda.
var Car = function(loc) {
var obj = {loc: loc};
extend(obj, Car.methods);
return obj;
};
Car.methods = {
move : function() {
this.loc++;
}
};
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
I primi due schemi consentono una discussione sull'uso delle tecniche per definire metodi condivisi o sull'uso di metodi definiti in linea nel corpo del costruttore. In entrambi i casi ogni istanza ha la sua move
funzione.
Il modello prototipo non si presta bene allo stesso esame, poiché la condivisione delle funzioni tramite una delegazione prototipo è l'obiettivo stesso del modello prototipo. Come altri hanno sottolineato, si prevede che abbia un footprint di memoria migliore.
Tuttavia, c'è un punto interessante da sapere: ogni prototype
oggetto ha una proprietà di convenienza constructor
, che rimanda alla funzione (pensa all'oggetto) a cui è stata assegnata.
Per quanto riguarda le ultime tre righe:
In questo esempio Car
collegamenti alla prototype
oggetto, che collega via constructor
alla Car
stessa, cioè Car.prototype.constructor
è Car
esso stesso. Ciò consente di capire quale funzione di costruzione ha creato un determinato oggetto.
amy.constructor
La ricerca fallisce e quindi viene delegata Car.prototype
, che ha la proprietà di costruzione. E così amy.constructor
è Car
.
Inoltre, amy
è un instanceof
Car
. L' instanceof
operatore funziona verificando se l'oggetto prototipo ( Car
) dell'operando destro si trova in qualsiasi punto della amy
catena prototype ( ) dell'operando sinistro .
var Car = function(loc) {
var obj = Object.create(Car.prototype);
obj.loc = loc;
return obj;
};
Car.prototype.move = function() {
this.loc++;
};
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);
Alcuni sviluppatori possono essere confusi all'inizio. Vedi l'esempio seguente:
var Dog = function() {
return {legs: 4, bark: alert};
};
var fido = Dog();
console.log(fido instanceof Dog);
Il instanceof
operatore ritorna false
, perché Dog
il prototipo del modello non può essere trovato da nessuna parte nella fido
catena del prototipo. fido
è un semplice oggetto che viene creato con un oggetto letterale, cioè solo a delega Object.prototype
.
Questa è davvero solo un'altra forma del modello prototipo in forma semplificata e più familiare per fare coloro che programmano in Java, ad esempio, poiché utilizza il new
costruttore.
Fa esattamente lo stesso del modello prototipo, è solo uno zucchero sintattico sopra il modello prototipo.
Tuttavia, la differenza principale è che ci sono ottimizzazioni implementate nei motori JavaScript che si applicano solo quando si utilizza il modello pseudoclassico. Pensa al modello pseudoclassico una versione probabilmente più veloce del modello prototipo; le relazioni dell'oggetto in entrambi gli esempi sono le stesse.
var Car = function(loc) {
this.loc = loc;
};
Car.prototype.move = function() {
this.loc++;
};
var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();
Infine, non dovrebbe essere troppo difficile capire come si possa fare una programmazione orientata agli oggetti. Ci sono due sezioni.
Una sezione che definisce proprietà / metodi comuni nel prototipo (catena).
E un'altra sezione in cui metti le definizioni che distinguono gli oggetti l'uno dall'altro (loc
variabile negli esempi).
Questo è ciò che ci consente di applicare concetti come superclasse o sottoclasse in JavaScript.
Sentiti libero di aggiungere o modificare. Ancora una volta completo, potrei rendere questo un wiki della comunità forse.
Credo che @Matthew Crumley abbia ragione. Sono funzionalmente , se non strutturalmente, equivalenti. Se usi Firebug per guardare gli oggetti creati usando new
, puoi vedere che sono gli stessi. Tuttavia, la mia preferenza sarebbe la seguente. Immagino che sembra più simile a quello a cui sono abituato in C # / Java. Cioè, definire la classe, definire i campi, il costruttore e i metodi.
var A = function() {};
A.prototype = {
_instance_var: 0,
initialize: function(v) { this._instance_var = v; },
x: function() { alert(this._instance_var); }
};
EDIT Non intendevo implicare che l'ambito della variabile fosse privato, stavo solo cercando di illustrare come definisco le mie classi in javascript. Il nome della variabile è stato modificato per riflettere questo.
initialize
e x methods do not refer to the
_instance_var` su A
un'istanza, ma su una globale. Utilizzare this._instance_var
se si intendeva utilizzare la _instance_var
proprietà di A
un'istanza.
Come discusso in altre risposte, è davvero una considerazione delle prestazioni perché la funzione nel prototipo è condivisa con tutte le istanze - piuttosto che la funzione creata per ogni istanza.
Ho messo insieme un jsperf per mostrarlo. C'è una differenza drammatica nel tempo impiegato per creare un'istanza della classe, anche se è davvero rilevante solo se stai facendo molte istanze.