我现在已经多次看过来自this question on class-free 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
。
答案 0 :(得分:8)
Crockford所说的“无类继承”实际上仍然是原型继承。实际上,有two types原型继承机制:
这就是我传统上编写面向对象的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>
&#13;
Crockford主张编写面向对象的JavaScript代码:
var superFlanker = FighterAircraft({
model: "Super Flanker",
speed: "Mach 2.25",
radar: "low"
});
superFlanker.describeFighterAircraft();
&#13;
<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>
&#13;
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();
&#13;
<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>
&#13;
this
是的,您可以在不使用this
的情况下使用mixins。但是,我不明白你为什么要这样做:
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();
&#13;
<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>
&#13;
有很多理由喜欢composition over inheritance:
我能想到的唯一缺点是,如果原型被修改,那么更改将不会反映在其实例上。但是,无论如何都没有理由改变原型。因此,我的mixins都被冷冻了。