如何在 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 的模式(它似乎根本不使用继承,而是从多个来源组合一个对象)在多种风格的模块之间共享这种基本结构?
我知道id
和model
将成为每个模块"构造函数"中的局部变量;我本质上是在问如何避免使用 Crockford 模式对每种风格的模块重复model = spec.model
。
Crockford所说的"无类继承"实际上仍然是原型继承。实际上,有两种类型的原型遗传机制:
- 通过委托进行原型继承(又称差异继承)。
- 通过克隆进行原型继承(又称串联遗传)。
差异原型遗传的一个例子
这就是我传统上编写面向对象的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更好地连接原型遗传
克罗克福德的拼接原型遗传方法有很多重复。另一种选择是:
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
使用混音
是的,您可以在不使用 this
的情况下使用 mixin。但是,我不明白你为什么要:
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>
串联继承的优点
选择组合而不是继承的原因有很多:
- 简单的多重继承。
- 更快的物业访问。
我能想到的唯一缺点是,如果修改了原型,那么更改将不会反映在其实例上。但是,无论如何都没有充分的理由更改原型。因此,我的混音都被冷冻了。
相关文章:
- ES6构造函数返回基类的实例
- 使用Google Visualization动态调用构造函数
- javascript中对象构造函数中的var属性与this.properties
- 理解typescript中的构造函数接口
- 为什么构造函数不是构造函数
- 如果在构造函数中有“返回”,则在 JavaScript 中的新运算符中做了什么
- 拦截对构造函数的调用
- 使用闭包共享构造函数参数
- 文本表示法VS.构造函数,用于在JavaScript中创建对象
- 从js引擎的角度来看闭包和构造函数是如何工作的
- 如何使用此从对象访问构造函数
- Javascript:为什么是构造函数's __proto__属性Empty(){}
- 当一个重要的构造函数参数丢失时应该发生什么
- Chrome Javascript日期构造函数错误
- 如何使用构造函数's的输出,以便将值插入到对象中
- 为什么在调用父构造函数时在[]中发送数据
- 构造函数函数闭包变量
- ES6类是否与构造函数相同
- 如何在 Crockford 的新构造函数模式中共享“构造函数”功能
- 防止构造函数的多个实例共享相同的原型属性