Perché l'utilizzo di costruttori è scoraggiato durante la creazione di prototipi?

10

Sfondo rapido: in JavaScript, la funzione di costruzione per ogni tipo di oggetto ha una proprietà prototype . Il prototype si riferisce a un oggetto che ogni oggetto costruito utilizza come passo successivo nella sua catena di prototipi. Quando vuoi che un tipo sia inerente ad un altro tipo, puoi impostare prototype del tipo figlio in una nuova istanza del tipo genitore.

Ad esempio:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

La mia domanda chiede quale codice dovrebbe andare nello spot " Some prototype object goes here " nel codice sopra. Il mio primo istinto è di costruire un'istanza del genitore (cioè, new Parent() ), ma in un commento ad una risposta su È un modo sicuro di copiare un prototipo di un oggetto in un altro? , un utente scrive:

No, do not use new bar() for the prototype object!

(... che è un'opinione che ho visto in molte risposte e commenti SO, ma questo è l'unico esempio che ho in mano al momento.)

L'altra opzione è usare Object.create(Parent.prototype) come Child.prototype . Per quanto ne so, questo crea anche una nuova istanza Parent , ma non esegue il costruttore Parent .

Qualcuno può spiegare perché l'esecuzione della funzione di costruzione dovrebbe essere evitata quando si genera un prototipo da un tipo genitore? Esiste qualche problema tecnico significativo (forse con più livelli di ereditarietà)? O è un tale modello un uso improprio dei costruttori che si scontra con alcune best practice prototipiche (ad esempio, l'esecuzione del costruttore quando si crea un prototipo viola una separazione delle preoccupazioni)?

    
posta apsillers 15.05.2013 - 19:19
fonte

2 risposte

5

Perché è una funzione che non ha bisogno di essere chiamata. new non è diverso da una chiamata di funzione normale in Javascript.

Un costruttore può fare di più che semplicemente impostare i campi. Ad esempio, se convalida i dati in entrata, allora causerai una convalida errore quando stavi semplicemente cercando di impostare la catena di ereditarietà.

E non hai bisogno di Object.create , questo è sufficiente:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}
    
risposta data 15.05.2013 - 19:34
fonte
2

Ora che la mia comprensione si è ampliata un po ', mi piacerebbe costruire su la risposta di Esailija con uno specifico esempio:

Una preoccupazione specifica è che un costruttore può impostare proprietà specifiche dell'istanza. Pertanto, se si utilizza un oggetto prototipo creato con new , tutte le istanze figlio potrebbero condividere una singola proprietà specifica dell'istanza definita dal costruttore dal prototipo.

Ad esempio, supponiamo che le istanze Parent abbiano ciascuna una proprietà id unica impostata come tempo di costruzione:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

Ciò causerà tutte Child istanze per condividere una singola proprietà prototipo id ereditata dal solo e unico new Parent() oggetto usato come Child.prototype .

Un approccio migliore per questo caso è utilizzare Object.create e chiamare direttamente il costruttore genitore (se necessario) all'interno del costruttore figlio:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run 'this' through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
    
risposta data 18.07.2014 - 13:08
fonte

Leggi altre domande sui tag