如何在 Javascript 中使用 mixin
How to use mixin in Javascript
大家好我有摘要class电脑:
class Computer {
constructor(manufacturer, processorSpeed, ram, hardDiskSpace) {
if (new.target === Computer) {
throw new Error("Cannot instantiate directly.");
}
this.manufacturer = manufacturer;
this.processorSpeed = Number(processorSpeed);
this.ram = Number(ram);
this.hardDiskSpace = Number(hardDiskSpace);
}
}
和桌面 class 扩展计算机 Class。
我正在尝试将 mixin 功能连接到计算机 Class,如下所示:
computerQualityMixin.call(Computer.prototype);
并将其与 class 桌面的对象一起使用。这是我的混合代码;
function computerQualityMixin() {
let ram = this.ram;
let processorSpeed = this.processorSpeed;
let hardDiskSpace = this.hardDiskSpace;
this.getQuality = () => {
return processorSpeed
* ram
* hardDiskSpace;
};
this.isFast = () => {
return processorSpeed > ram / 4;
};
this.isRoomy = () => {
return hardDiskSpace > Math.floor(ram * processorSpeed);
};
}
问题是我得到了我尝试获得的所有属性的 'undefined':'this.ram' 例如在我的 mixin 中,当我调用某个函数时:
let desktop = new Desktop("JAR Computers", 3.3, 8, 1);
console.log(desktop.getQuality());//Returns NaN because try to make Math operations with 'undefined'
有人可以帮助我理解 mixins 吗?谢谢。
这些评论提出了很好的问题,即您是否真的想在这里使用 mixins。但如果你这样做,你可能想看看 Angus Croll and Reg Braithwaite
的文章
使用前者的技术,您可以重写为
const asComputerQuality = function() {
this.getQuality = function() {
return this.processorSpeed
* this.ram
* this.hardDiskSpace;
};
this.isFast = function() {
return this.processorSpeed > this.ram / 4;
};
this.isRoomy = function() {
return this.hardDiskSpace > Math.floor(this.ram * this.processorSpeed);
};
}
asComputerQuality.call(Computer.prototype);
那么您应该能够在 Computer
个实例上调用这些方法。
Mixins 应该被视为一种方便的代码重用形式。
描述对象特定行为的代码,以及
往往被一遍又一遍地复制,可能会被考虑
曾经 collected/stored 成为混音。
使用 JavaScript 中基于 mixin/trait 模式的函数
还可以利用其提供的有状态变体
人们可能会如何安排的更多可能性
type/object 个架构。
正如已经指出的那样,OP 的示例不太好
根据适合 mixin/trait 的构图选择。
下一个给定的代码块仍然会稍微尝试一下
改变变体以展示不同的方法
在 JavaScript ...
中应用基于函数的 mixin/trait 模式
function withObjectBaseIntrospection(state) { // - mixin that preserves injected
var // local state by creating a
object = this; // closure at call/apply time.
object.valueOf = function () {
return Object.assign({}, state);
};
object.toString = function () {
return JSON.stringify(state);
};
}
function withHardwareStandardGetters(state) { // - mixin that preserves injected
var // local state by creating a
hardware = this; // closure at call/apply time.
Object.defineProperty(hardware, "manufacturer", {
get: function () { return state.manufacturer; }
});
Object.defineProperty(hardware, "processorSpeed", {
get: function () { return state.processorSpeed; }
});
Object.defineProperty(hardware, "ram", {
get: function () { return state.ram; }
});
Object.defineProperty(hardware, "hardDiskSpace", {
get: function () { return state.hardDiskSpace; }
});
}
function withDesktopSpecificGetters(state) { // - mixin that preserves injected
var // local state by creating a
hardware = this; // closure at call/apply time.
Object.defineProperty(hardware, "bodyLength", {
get: function () { return state.bodyLength; }
});
Object.defineProperty(hardware, "bodyWidth", {
get: function () { return state.bodyWidth; }
});
Object.defineProperty(hardware, "bodyHeight", {
get: function () { return state.bodyHeight; }
});
}
function withHardwareSpecificQuality() { // - generic function based mixin pattern.
this.getQuality = function() {
return (this.processorSpeed * this.ram * this.hardDiskSpace);
};
this.isFast = function () {
return (this.processorSpeed > (this.ram / 4));
};
this.isRoomy = function () {
return (this.hardDiskSpace > Math.floor(this.ram * this.processorSpeed));
};
}
function withDesktopSpecificMeasures() { // - generic function based mixin pattern.
this.getBodyVolume = function() {
return (this.bodyLength * this.bodyWidth * this.bodyHeight);
};
}
class Computer {
constructor(state) {
withObjectBaseIntrospection.call(this, state); // - applying 2 "stateful mixin"
withHardwareStandardGetters.call(this, state); // at instance/object level.
}
}
withHardwareSpecificQuality.call(Computer.prototype); // - making use of inheritance via the
// constructor's prototype, but enriching the
// latter by a more generic mixin (at "class level").
class Desktop extends Computer { // - newly available
constructor(state) { // syntactic sugar for the more
// "class like" inheritance pattern.
super(state);
withDesktopSpecificGetters.call(this, state); // - applying a "stateful mixin"
} // at instance/object level.
}
withDesktopSpecificMeasures.call(Desktop.prototype); // - making use of inheritance via the
// constructor's prototype, but enriching the
// latter by a more generic mixin (at "class level").
let
desktop = new Desktop({
manufacturer: "JAR Computers",
processorSpeed: 3.3,
ram: 8,
hardDiskSpace: 1,
bodyWidth: 300,
bodyHeight: 40,
bodyLength: 300
});
console.log("Desktop.prototype : ", Desktop.prototype);
console.log("Computer.prototype : ", Computer.prototype);
console.log("(desktop instanceof Desktop) ? ", (desktop instanceof Desktop));
console.log("(desktop instanceof Computer) ? ", (desktop instanceof Computer));
console.log("desktop.manufacturer : ", desktop.manufacturer);
console.log("desktop.processorSpeed : ", desktop.processorSpeed);
console.log("desktop.ram : ", desktop.ram);
console.log("desktop.hardDiskSpace : ", desktop.hardDiskSpace);
console.log("desktop.getQuality() : ", desktop.getQuality());
console.log("desktop.getBodyVolume() : ", desktop.getBodyVolume());
console.log("desktop.valueOf() : ", desktop.valueOf());
console.log("desktop.toString() : ", desktop.toString());
人们也可以考虑看一个更好的 JavaScript 示例,它也试图证明 when to use inheritance via class extension and when not, when to use just mixin/trait based composition and also when to use both。
旁注 - JavaScript
中关于基于 Mixins/Traits/Taltens 的函数的推荐资源
- A fresh look at JavaScript Mixins 安格斯·克罗尔自 2011 年 5 月起
- The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins 自 2014 年 4 月起。
此外,我确实建议阅读我在 SO 上给出的一些列出的答案,它们也与该主题相关。
- ES 6 Classes - Mixins
- How to use mixins properly in Javascript
- Traits in javascript
大家好我有摘要class电脑:
class Computer {
constructor(manufacturer, processorSpeed, ram, hardDiskSpace) {
if (new.target === Computer) {
throw new Error("Cannot instantiate directly.");
}
this.manufacturer = manufacturer;
this.processorSpeed = Number(processorSpeed);
this.ram = Number(ram);
this.hardDiskSpace = Number(hardDiskSpace);
}
}
computerQualityMixin.call(Computer.prototype);
并将其与 class 桌面的对象一起使用。这是我的混合代码;
function computerQualityMixin() {
let ram = this.ram;
let processorSpeed = this.processorSpeed;
let hardDiskSpace = this.hardDiskSpace;
this.getQuality = () => {
return processorSpeed
* ram
* hardDiskSpace;
};
this.isFast = () => {
return processorSpeed > ram / 4;
};
this.isRoomy = () => {
return hardDiskSpace > Math.floor(ram * processorSpeed);
};
}
let desktop = new Desktop("JAR Computers", 3.3, 8, 1);
console.log(desktop.getQuality());//Returns NaN because try to make Math operations with 'undefined'
有人可以帮助我理解 mixins 吗?谢谢。
这些评论提出了很好的问题,即您是否真的想在这里使用 mixins。但如果你这样做,你可能想看看 Angus Croll and Reg Braithwaite
的文章使用前者的技术,您可以重写为
const asComputerQuality = function() {
this.getQuality = function() {
return this.processorSpeed
* this.ram
* this.hardDiskSpace;
};
this.isFast = function() {
return this.processorSpeed > this.ram / 4;
};
this.isRoomy = function() {
return this.hardDiskSpace > Math.floor(this.ram * this.processorSpeed);
};
}
asComputerQuality.call(Computer.prototype);
那么您应该能够在 Computer
个实例上调用这些方法。
Mixins 应该被视为一种方便的代码重用形式。
描述对象特定行为的代码,以及 往往被一遍又一遍地复制,可能会被考虑 曾经 collected/stored 成为混音。
使用 JavaScript 中基于 mixin/trait 模式的函数 还可以利用其提供的有状态变体 人们可能会如何安排的更多可能性 type/object 个架构。
正如已经指出的那样,OP 的示例不太好 根据适合 mixin/trait 的构图选择。
下一个给定的代码块仍然会稍微尝试一下 改变变体以展示不同的方法 在 JavaScript ...
中应用基于函数的 mixin/trait 模式function withObjectBaseIntrospection(state) { // - mixin that preserves injected
var // local state by creating a
object = this; // closure at call/apply time.
object.valueOf = function () {
return Object.assign({}, state);
};
object.toString = function () {
return JSON.stringify(state);
};
}
function withHardwareStandardGetters(state) { // - mixin that preserves injected
var // local state by creating a
hardware = this; // closure at call/apply time.
Object.defineProperty(hardware, "manufacturer", {
get: function () { return state.manufacturer; }
});
Object.defineProperty(hardware, "processorSpeed", {
get: function () { return state.processorSpeed; }
});
Object.defineProperty(hardware, "ram", {
get: function () { return state.ram; }
});
Object.defineProperty(hardware, "hardDiskSpace", {
get: function () { return state.hardDiskSpace; }
});
}
function withDesktopSpecificGetters(state) { // - mixin that preserves injected
var // local state by creating a
hardware = this; // closure at call/apply time.
Object.defineProperty(hardware, "bodyLength", {
get: function () { return state.bodyLength; }
});
Object.defineProperty(hardware, "bodyWidth", {
get: function () { return state.bodyWidth; }
});
Object.defineProperty(hardware, "bodyHeight", {
get: function () { return state.bodyHeight; }
});
}
function withHardwareSpecificQuality() { // - generic function based mixin pattern.
this.getQuality = function() {
return (this.processorSpeed * this.ram * this.hardDiskSpace);
};
this.isFast = function () {
return (this.processorSpeed > (this.ram / 4));
};
this.isRoomy = function () {
return (this.hardDiskSpace > Math.floor(this.ram * this.processorSpeed));
};
}
function withDesktopSpecificMeasures() { // - generic function based mixin pattern.
this.getBodyVolume = function() {
return (this.bodyLength * this.bodyWidth * this.bodyHeight);
};
}
class Computer {
constructor(state) {
withObjectBaseIntrospection.call(this, state); // - applying 2 "stateful mixin"
withHardwareStandardGetters.call(this, state); // at instance/object level.
}
}
withHardwareSpecificQuality.call(Computer.prototype); // - making use of inheritance via the
// constructor's prototype, but enriching the
// latter by a more generic mixin (at "class level").
class Desktop extends Computer { // - newly available
constructor(state) { // syntactic sugar for the more
// "class like" inheritance pattern.
super(state);
withDesktopSpecificGetters.call(this, state); // - applying a "stateful mixin"
} // at instance/object level.
}
withDesktopSpecificMeasures.call(Desktop.prototype); // - making use of inheritance via the
// constructor's prototype, but enriching the
// latter by a more generic mixin (at "class level").
let
desktop = new Desktop({
manufacturer: "JAR Computers",
processorSpeed: 3.3,
ram: 8,
hardDiskSpace: 1,
bodyWidth: 300,
bodyHeight: 40,
bodyLength: 300
});
console.log("Desktop.prototype : ", Desktop.prototype);
console.log("Computer.prototype : ", Computer.prototype);
console.log("(desktop instanceof Desktop) ? ", (desktop instanceof Desktop));
console.log("(desktop instanceof Computer) ? ", (desktop instanceof Computer));
console.log("desktop.manufacturer : ", desktop.manufacturer);
console.log("desktop.processorSpeed : ", desktop.processorSpeed);
console.log("desktop.ram : ", desktop.ram);
console.log("desktop.hardDiskSpace : ", desktop.hardDiskSpace);
console.log("desktop.getQuality() : ", desktop.getQuality());
console.log("desktop.getBodyVolume() : ", desktop.getBodyVolume());
console.log("desktop.valueOf() : ", desktop.valueOf());
console.log("desktop.toString() : ", desktop.toString());
人们也可以考虑看一个更好的 JavaScript 示例,它也试图证明 when to use inheritance via class extension and when not, when to use just mixin/trait based composition and also when to use both。
旁注 - JavaScript
中关于基于 Mixins/Traits/Taltens 的函数的推荐资源- A fresh look at JavaScript Mixins 安格斯·克罗尔自 2011 年 5 月起
- The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins 自 2014 年 4 月起。
此外,我确实建议阅读我在 SO 上给出的一些列出的答案,它们也与该主题相关。
- ES 6 Classes - Mixins
- How to use mixins properly in Javascript
- Traits in javascript