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 né 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, comeD <- ((((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?