JavaScript esteso vs mixin

5

Dopo aver letto l'articolo di Fluent JavaScript di Eric Elliott , Ero e sono ancora pieno di idee sul modo di giocare con i prototipi di istanza.

Da un lato, hai l'eredità che estende ...

var B = function() {} ;
B.prototype = new A() ;

O il nuovo modo di farlo ...

B.prototype = Object.create(A.prototype) ;

E dall'altra parte, hai mixin , creando un mix di più prototipi che saranno ereditati dalle istanze.

var B = function() {} ;
// Basic mixin from A
for (var m in A.prototype) B.prototype[m] = A.prototype[m] ;
  • Nel suo articolo, Eric Elliott ci incoraggia ad evitare di estendere i tipi ma a comporre (mixin) una sorta di componenti oggetti / prototipi (vedi anche Stampit on github ). Sono assolutamente d'accordo.

  • Tuttavia, sembra interrompere una delle principali funzionalità (e filosofia) in JavaScript: Modularità . Ciò che intendo è il fatto che la modifica dei prototipi sarà automaticamente disponibile per tutte le istanze mediante riferimenti.

Ecco un esempio di base dell'ereditarietà del prototipo:

var A = function() {} ;
A.prototype.fn = function() { return 1 ; } ;

var a = new A() ;
a.fn() ; // 1

A.prototype.fn = function() { return 2 ; } ;
a.fn() ; // 2

E ora con un prototipo esteso:

var B = function() {} ;
B.prototype = Object.create(A.prototype) ;

var b = new B() ;
b.fn() ; // 2, inherited from A.prototype

Va bene, funziona bene, ma non possiamo ereditare da più prototipi; più l'ereditarietà classica è generalmente evitata.

L'altra soluzione sarebbe quindi mixin:

var D = function() {} ;
// Let's imagine a mixin function mixing D with some prototypes...
mixin(D, A.prototype, C.prototype, R.prototype) ;

var d = new D() ;
d.fn() ; // 2, inherited from A.prototype ? Let's see...

A.prototype.fn = function() { return 3 ; } ;
d.fn() ; // 2, what a shame...

In effetti, mixin copia solo tutte le funzioni da un prototipo a un altro. Questo significa che non ci sono più riferimenti tra questi tipi e quindi la modularità sembra interrotta qui (testata anche con Stampit).

Sto pensando a una soluzione innovativa per mantenere i riferimenti agli oggetti prototipo originali e non solo le funzioni all'interno.

E le eredità a cascata?

  • Non come D <- C <- B <- A , poiché altera B e C e sembra restrittivo.

  • Ma come D <- (((p <- A) <- B) <- C) , dove p è un prototipo privato riservato solo a D . Né B C verranno modificati, solo p sarà un'eredità a cascata diretta. D avrà tutti i metodi dai prototipi elencati, e se vogliamo ereditare da un altro, riavvia il processo da zero, come D <- ((((p <- A) <- B) <- C) <- R) .

L'unico inconveniente che vedo riguarda le performance. Ogni volta che aggiungiamo una nuova ereditarietà, dovremo riavviare l'intero processo: infatti, dopo aver ereditato, aggiungiamo nuove funzioni al prototipo (o sovrascriviamo alcune), e questo deve essere sempre alla fine del processo, quindi dopo R ereditari:

  • Prima: D <- ((((p <- A) <- B) <- C) <- {}) dove {} è l'insieme di nuove funzioni / sovrascrittura.

  • Dopo: D <- (((((p <- A) <- B) <- C) <- R) <- {}) , e non ... <- {}) <- R) .

Sarebbe interessante avere una piccola libreria per questo? Sarei pronto a farlo, consentendo più eredità di prototipo.

Quindi ... cosa ne pensi di tutto questo?

    
posta Tot 18.09.2015 - 00:33
fonte

1 risposta

2

Con Stampit, non c'è intenzionalmente nessun collegamento tra i prototipi mixin e la fonte originale, e questo è di progettazione, perché alterare il prototipo di ogni istanza potrebbe quindi alterare il prototipo originale.

Nel tuo post, sembra che tu pensi che sia una brutta cosa, ma in pratica, la mutazione dei prototipi dopo l'istanziazione degli oggetti ha una miriade di effetti collaterali ad ampio raggio che possono avere un impatto significativo sulla robustezza dell'app (è molto più difficile da capire quali cambiamenti avranno un impatto su quali oggetti, ad esempio, pensi di correggere un bug nelle animazioni sprite e improvvisamente il tuo motore di rendering delle particelle si rompe, perché condividono un prototipo comune) e le prestazioni (la modifica dei prototipi causa la perdita di tutti i motori JS le ottimizzazioni delle proprietà dell'oggetto memorizzato nella cache, incluse le ottimizzazioni che influiscono sul perfetto ogni pezzo di codice che utilizza qualsiasi oggetto discendente ).

In altre parole, quello che stai cercando di fare è ampiamente considerato un anti-pattern nella comunità JavaScript.

Un altro punto interessante: la nuova specifica del timbro ti consente di passare un'istanza nel timbro. Se lo fai, il timbro non altererà il prototipo originale e il prototipo originale apparirà nella catena del prototipo, il che significa che ciò che stai suggerendo sarà possibile nella prossima versione di Stampit - ma il mio avvertimento che altera i prototipi dopo l'istanziazione è ancora presente un anti-pattern.

    
risposta data 22.09.2015 - 22:15
fonte

Leggi altre domande sui tag