簡體   English   中英

如何在Crockford的新構造函數模式中共享“構造函數”功能?

[英]How do I share “constructor” functionality in Crockford's new constructor pattern?

我現在已經多次在無類OOP上觀看了這個問題的視頻,而我在將這個應用到現實世界的例子中時遇到了麻煩。

Crockford的新構造函數模式如下所示:

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

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

其中spec是一個選項哈希,結果對象公開了關閉所有內部成員的方法。 忽略解構(因為這可以在現今的JS中以長篇形式完成) ,我如何在現實世界的例子中應用這種模式?

我目前有一個帶有基類Module(model, id)的庫,其中model是一些引導數據。

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

然后我有幾種類型的模塊繼承自這個父Module 在Crockford的模式下,我會把它作為“構造函數”:

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

    return Object.freeze({});
}

我如何使用Crockford的模式(它似乎根本不使用繼承,而是從多個源組成一個對象) 在多種模塊之間共享這種基本結構

我知道idmodel將成為每個模塊的“構造函數”中的局部變量; 我基本上問如何避免使用Crockford模式為每種模塊重復model = spec.model

Crockford所說的“無類繼承”實際上仍然是原型繼承。 實際上,有兩種 類型的原型繼承機制:

  1. 通過委托(又稱差異繼承)進行原型繼承。
  2. 通過克隆(aka連接繼承)進行原型繼承。

差異原型繼承的一個例子

這就是我傳統上編寫面向對象的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> 

連接原型繼承的一個例子

這就是Crockford倡導編寫面向對象的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> 

使用mixins更好的連鎖原型繼承

Crockford的連接原型繼承方法有很多重復。 另一種選擇是:

 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> 

沒有this使用mixins

是的,你可以使用mixins而不使用this 但是,我不明白你為什么要這樣做:

 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> 

連接繼承的優點

有很多理由喜歡組合而不是繼承

  1. 簡單的多重繼承。
  2. 更快的財產訪問。

我能想到的唯一缺點是,如果原型被修改,那么更改將不會反映在其實例上。 但是,無論如何都沒有充分的理由改變原型。 因此,我的mixins都被冷凍了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM