2015-01-10 18 views
7

Ho guardato il video da this question on class-free OOP diverse volte e ho difficoltà ad applicarlo a un esempio reale.Come posso condividere la funzionalità "costruttore" nel nuovo modello di costruttore di Crockford?

di Crockford modello nuovo costruttore si presenta così:

function constructor(spec) { 
    let {member} = spec, 
     {other} = other_constructor(spec), 
     method = function() { 
     // accesses member, other, method, spec 
     }; 

    return Object.freeze({ 
     method, 
     other, 
    }); 
} 

Dove spec è un hash opzioni e l'oggetto risultante espone i metodi che chiudono su tutte le componenti interne. Ignorando la destrutturazione (come questo può essere fatto in forma lunga nell'attuale JS,) come posso applicare questo modello in un esempio reale?

Attualmente ho una libreria con una classe di base Module(model, id) dove model sono alcuni dati di avvio.

// constructor, original flavor 
function Module(model, id) { 
    this.id = id; 
    this.model = model; 
} 

Ho poi hanno diversi sapori di moduli che ereditano da questo genitore Module. Sotto modello di Crockford, vorrei invece avere questo come un "costruttore":

// constructor, Crockford's Cool Ranch 
function module(spec) { 
    let id = spec.id, 
     model = spec.model; 

    return Object.freeze({}); 
} 

Come faccio a usare modello di Crockford (che non sembra utilizzare l'ereditarietà a tutti, ma piuttosto la composizione di un oggetto da più fonti) a condividere questa costruzione di base tra più sapori dei moduli?

So che id e model diventeranno variabili locali nel "costruttore" di ciascun modulo; In sostanza, sto chiedendo come evitare di ripetere model = spec.model per ciascun aroma del modulo usando il modello di Crockford.

+0

Vorrei anche essere il primo a sottolineare qui che, in quell'altra domanda, ho avuto credito per una risposta che non capisco. :( – Mathletics

+0

non puoi, stai mescolando le metafore qui, la 3a scatola non è come la 2a scatola, la terza restituisce un oggetto vuoto senza proto, la 2 restituisce un oggetto personalizzato con un proto e 2 possiede. crockford's restituisce un oggetto non proto con _n_: è come avere la semplicità del prototipo (ottenendo una serie di metodi contemporaneamente, in quel caso da _other_ invece di _prototype_), ma senza iterarli tutti come facciamo ora tramite extend() strumenti – dandavis

+0

@dandavis So che nella seconda casella le proprietà sono esposte e nella terza sono private.Se ignoriamo completamente la seconda casella, la risposta è la stessa? Non c'è modo di evitare di ripetere il codice di configurazione necessario per assegnando membri privati ​​in ciascun aroma del modulo? – Mathletics

risposta

8

Ciò che Crockford chiama l'ereditarietà senza classe “ ” è in realtà ancora un'eredità prototipale. In realtà, ci sono twotypes di meccanismi ereditarietà prototipale:

  1. ereditarietà prototipale tramite delega (ereditarietà differenziale pseudonimo).
  2. Eredità prototipale tramite clonazione (a.k.a ereditarietà concatenativa).

Un esempio di ereditarietà prototipale differenziale

questo è come tradizionalmente scrivere orientato agli oggetti codice JavaScript:

var Aircraft = defclass({ 
 
    constructor: function (model, speed) { 
 
     this.model = model; 
 
     this.speed = speed; 
 
    }, 
 
    describeAircraft: function() { 
 
     alert("The " + this.model + " flies at " + this.speed + " speed."); 
 
    } 
 
}); 
 

 
var FighterAircraft = extend(Aircraft, { 
 
    constructor: function (model, speed, radar) { 
 
     Aircraft.call(this, model, speed); 
 
     this.radar = radar; 
 
    }, 
 
    describeFighterAircraft: function() { 
 
     this.describeAircraft(); 
 
     alert("It has a " + this.radar + " radar signature."); 
 
    } 
 
}); 
 

 
var superFlanker = new FighterAircraft("Super Flanker", "Mach 2.25", "low"); 
 

 
superFlanker.describeFighterAircraft();
<script> 
 
function defclass(prototype) { 
 
    var constructor = prototype.constructor; 
 
    constructor.prototype = prototype; 
 
    return constructor; 
 
} 
 

 
function extend(constructor, properties) { 
 
    var prototype = Object.create(constructor.prototype); 
 
    for (var name in properties) prototype[name] = properties[name]; 
 
    return defclass(prototype); 
 
} 
 
</script>

Un esempio di concatenative ereditarietà prototipale

Ecco come Crockford sostenitori di scrivere orientato agli oggetti codice JavaScript:

var superFlanker = FighterAircraft({ 
 
    model: "Super Flanker", 
 
    speed: "Mach 2.25", 
 
    radar: "low" 
 
}); 
 

 
superFlanker.describeFighterAircraft();
<script> 
 
function Aircraft(spec) { 
 
    var model = spec.model; 
 
    var speed = spec.speed; 
 

 
    function describeAircraft() { 
 
     alert("The " + model + " flies at " + speed + " speed."); 
 
    } 
 

 
    return Object.freeze({ 
 
     model: model, 
 
     speed: speed, 
 
     describeAircraft: describeAircraft 
 
    }); 
 
} 
 

 
function FighterAircraft(spec) { 
 
    var aircraft = Aircraft(spec); 
 
    var model = spec.model; 
 
    var speed = spec.speed; 
 
    var radar = spec.radar; 
 

 
    function describeFighterAircraft() { 
 
     aircraft.describeAircraft(); 
 
     alert("It has a " + radar + " radar signature."); 
 
    } 
 

 
    return Object.freeze({ 
 
     model: model, 
 
     speed: speed, 
 
     radar: radar, 
 
     describeFighterAircraft: describeFighterAircraft 
 
    }); 
 
} 
 
</script>

Meglio concatenativa ereditarietà prototipale utilizzando mixins

modalità di ereditarietà prototipale concatenativa di Crockford ha un sacco di ripetizioni. Un'alternativa è:

var aircraft = mixin({ 
 
    describeAircraft: function() { 
 
     alert("The " + this.model + " flies at " + this.speed + " speed."); 
 
    } 
 
}); 
 

 
var fighterAircraft = mixin(aircraft, { 
 
    describeFighterAircraft: function() { 
 
     this.describeAircraft(); 
 
     alert("It has a " + this.radar + " radar signature."); 
 
    } 
 
}); 
 

 
var superFlanker = fighterAircraft({ 
 
    model: "Super Flanker", 
 
    speed: "Mach 2.25", 
 
    radar: "low" 
 
}); 
 

 
superFlanker.describeFighterAircraft();
<script> 
 
function mixin() { 
 
    var length = arguments.length; 
 
    var index = 0; 
 

 
    while (index < length) { 
 
     var properties = arguments[index++]; 
 
     for (var name in properties) 
 
      constructor[name] = properties[name]; 
 
    } 
 

 
    return Object.freeze(constructor); 
 

 
    function constructor(object) { 
 
     for (var name in constructor) 
 
      object[name] = constructor[name]; 
 
     return Object.freeze(object); 
 
    } 
 
} 
 
</script>

Utilizzando mixins senza this

Sì, è possibile utilizzare mixins senza utilizzare this. Tuttavia, non vedo il motivo per cui si vorrebbe:

var aircraft = mixin({ 
 
    describeAircraft: function (aircraft) { 
 
     alert("The " + aircraft.model + " flies at " + 
 
      aircraft.speed + " speed."); 
 
    } 
 
}); 
 

 
var fighterAircraft = mixin(aircraft, { 
 
    describeFighterAircraft: function (fighterAircraft) { 
 
     fighterAircraft.describeAircraft(); 
 
     alert("It has a " + fighterAircraft.radar + " radar signature."); 
 
    } 
 
}); 
 

 
var superFlanker = fighterAircraft({ 
 
    model: "Super Flanker", 
 
    speed: "Mach 2.25", 
 
    radar: "low" 
 
}); 
 

 
superFlanker.describeFighterAircraft();
<script> 
 
function mixin() { 
 
    var length = arguments.length; 
 
    var index = 0; 
 

 
    while (index < length) { 
 
     var properties = arguments[index++]; 
 
     for (var name in properties) 
 
      constructor[name] = properties[name]; 
 
    } 
 

 
    return Object.freeze(constructor); 
 

 
    function constructor(object) { 
 
     for (var name in constructor) { 
 
      var value = constructor[name]; 
 
      object[name] = typeof value === "function" ? 
 
       value.bind(null, object) : value; 
 
     } 
 

 
     return Object.freeze(object); 
 
    } 
 
} 
 
</script>

vantaggi dell'ereditarietà concatenativa

Ci sono molte ragioni per preferire composition over inheritance:

  1. semplice multipla eredità.
  2. Accesso alla proprietà più rapido.

L'unico svantaggio che posso pensare è che se il prototipo viene modificato, la modifica non si rifletterà sulle sue istanze. Tuttavia, non ci sono buoni motivi per cambiare il prototipo in ogni caso. Quindi, i miei mixin sono tutti congelati.

+0

È possibile utilizzare un pattern di mixin senza usare 'this'? L'approccio di Crockford evita sia "questo" che "nuovo" e mi piacerebbe poterlo fare anche io. – Mathletics

+0

Sì, è davvero possibile. Ho aggiornato la mia risposta per mostrare come. Tuttavia, non vedo alcuna ragione per farlo. Cosa c'è di sbagliato nell'usare "questo"? –

+0

In generale, niente, lo uso in abbondanza. Ma il mio attuale progetto è il software pubblicitario e mi piacerebbe provare a seguire le linee guida [AdSafe] (http://www.adsafe.org/) (oltre a provare a passare a una pratica di programmazione più funzionale per correggere alcune _stancabile_ abitudini di programmazione dei miei colleghi.) – Mathletics

Problemi correlati