2015-05-27 11 views
7

So che ci sono domande simili come questa, ma voglio vedere se quelle risposte sono ancora valide date le ottimizzazioni nei nuovi motori Javascript.Funzioni all'interno del costruttore vs prototipo

A mio parere, il più grande vantaggio sulla definizione funzioni all'interno del costruttore è che si può facilmente evitare di dover conoscere il valore di 'questo' parola chiave:

var Person = function() { 
    var self = this; 
    self.firstName = null; 
    self.lastName = null; 
    self.fullName = function() { 
    return self.firstName + self.lastName; 
    }; 
}; 

Questo approccio è consigliato da Knockout Managing 'this'. Questo è un grande vantaggio, specialmente quando il codice viene modificato da molti sviluppatori in quanto è molto semplice da capire e da usare.

L'altro approccio sarebbe quello di utilizzare il prototipo dell'oggetto:

var Person = function() { 
    this.firstName = null; 
    this.lastName = null; 
}; 
Person.prototype.fullName = function() { 
    return this.firstName + this.lastName; 
}; 

In questo caso ci sono vantaggi prestazionali perché funzioni oggetti viene creato quando. Tuttavia il problema principale che ho con esso è che potrebbe essere complicato gestire la parola chiave "this". L'esempio sopra è molto semplice, ma se si hanno gestori di eventi, per chiamate Ogni, chiamate jQuery each(), metodi chiamati da contesti diversi, ecc., È facile fare un cattivo uso di questo.

Naturalmente, se si capisce come "questo" funzioni e siano consapevoli di come vengono chiamati i metodi, non si dovrebbero avere molti problemi. Tuttavia, nella mia esperienza, questo richiede tempo ed è soggetto a errori, specialmente quando il codice è creato da molti sviluppatori.

So che i nuovi motori JS, come V8, applicano le ottimizzazioni ai casi in cui si dichiarano funzioni all'interno del costruttore mediante la creazione di classi nascoste: How the V8 engine works?.

Quindi la mia domanda è, date queste ottimizzazioni fatte dai nuovi motori JS e la complessità di dover gestire la parola chiave "this", ha ancora senso utilizzare l'approccio basato sul prototipo? Cosa avrei perso usando l'approccio di mettere tutto all'interno del costruttore?

UPDATE 1:

Ho appena fatto un micro-benchmark su Chrome (versione 42). Creo oggetti 1M con funzioni all'interno del costruttore e funzioni in prototipo. E 'un oggetto molto semplice con due variabili e tre funzioni ed i risultati sono simili:

Functions inside constructor: 1.91 seconds 
Functions in prototype: 1.10 seconds 

Suona come anche con tali ottimizzazioni in V8 è ancora 73% più velocemente. Tuttavia questo era un micro-benchmark. Non sono sicuro che questa sarà una grande differenza nelle applicazioni del mondo reale.

UPDATE 2:

ho anche preso uno sguardo al consumo di memoria e non ci sono grandi differenze pure. Per le funzioni costruttori interna:

Shallow size: 64,000,120 
Retained size: 336,001,128 

Per le funzioni di prototipo:

Shallow size: 40,000,000 
Retained size: 40,000,000 

Entrambi ottimizzazioni con classe di nascosto che non sono buone o mi manca qualcosa. Sto usando il codice monomorfico (costruttori senza argomenti) come suggerito dal V8, ma non sono sicuro se sto facendo qualcosa di sbagliato.

UPDATE 3:

Ecco il link del test che ho fatto nel caso in cui qualcuno può indicare qualcosa che non va in là: http://jsperf.com/dg-constructor-vs-prototype

+0

FWIW, ho aggiunto un terzo banco di prova, il "POJO" che non utilizza prototipo o la "nuova" parola chiave, semplicemente crea un oggetto con metodi pubblici e variabili private. È paragonabile nelle prestazioni all'esempio del costruttore. In entrambi i casi, il metodo prototipo è costantemente più veloce, anche se con la complessità aggiunta. http://jsperf.com/dg-constructor-vs-prototype/2 –

+0

Grazie Scott. Sì, sembra che in questo momento il modo più efficiente sia usare il prototipo. È un peccato perché amo la semplicità di assegnare "questo" a "sé" ed essere sicuro che il "sé" punta all'oggetto invece di dover pensare a cosa "questo" indica. – dgaviola

+0

Sì, sono completamente d'accordo. Per oggetti semplici (senza ereditarietà), l'uso di 'prototype' non è altro che una micro ottimizzazione, con l'inconveniente di dover comprendere e gestire attentamente l'uso di' this'. –

risposta

3

effettuo un test rapido. Se si dichiara la funzione nel costruttore, due istanze di oggetto hanno istanze di funzione diverse anche dopo le ottimizzazioni. Tuttavia con il prototipo, hai solo un'istanza della funzione che spiega la differenza di prestazioni.

var Person = function() { 
 
     var self = this; 
 
     self.firstName = null; 
 
     self.lastName = null; 
 
     self.fullName = function() { 
 
      return self.firstName + self.lastName; 
 
     }; 
 
    }; 
 

 
    Person.prototype.fullName2 = function() { 
 
     return this.firstName + this.lastName; 
 
    }; 
 

 
    var a = new Person(); 
 
    var b = new Person(); 
 

 
    console.log(a.fullName == b.fullName); // returns false 
 
    console.log(a.fullName2 == b.fullName2); // returns true

+0

Sì, ho aggiornato la domanda con alcuni test che ho fatto. Non dovrebbe creare una funzione quando si utilizzano le ottimizzazioni? Mi chiedo se gli oggetti debbano essere creati in un modo speciale per trarre vantaggio da questa ottimizzazione. – dgaviola

+0

Sembra che non ci sia modo di ottimizzare. Anche se v8 crea classi nascoste, le funzioni all'interno del costruttore sono variabili d'istanza. L'unica soluzione che posso pensare è usare il prototipo e, come 'self', definire' var pro = Person.prototype; '. Quindi invece di 'self.fullName = function()' usa 'pro.fullName = function()'. Almeno il codice sarà simile :) Per il problema 'this', qualcosa come http://think-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/ per jQuery potrebbe essere applicato . –

+0

Il vantaggio dell'uso di "sé" è che puoi usare ovunque sapendo che punterà all'oggetto. Sto usando alcune soluzioni alternative simili a quello che dici, ma devi ricordarti di farlo. Ma sì, probabilmente non ci sono altre scelte finora per essere efficienti. – dgaviola

Problemi correlati