如何在Javascript

时间:2016-11-06 20:53:27

标签: javascript oop ecmascript-6 mixins composition

大家好我有抽象类电脑:

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);
    }
}
而Desktop类扩展了计算机类。 我正在尝试将mixin功能挂钩到Computer Class,如下所示:

computerQualityMixin.call(Computer.prototype);

并将其与Desktop类对象一起使用。这是我的mixin代码;

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);
    };
}
问题是我得到了所有属性的“未定义”:例如在我的mixin中,'this.ram',当我调用某个函数时:

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吗?谢谢。

2 个答案:

答案 0 :(得分:0)

这些评论提出了一个很好的问题,即你是否真的想在这里使用mixins。但是,如果您这样做,您可能希望按Angus CrollReg 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个实例上调用这些方法。

答案 1 :(得分:0)

应该将Mixins视为一种方便的代码重用形式。

描述对象的某些行为的代码 往往会被一遍又一遍地复制,可能会被考虑 被收集/存储一次到混合物中。

使用JavaScript中基于函数的mixin / trait模式 人们也可以利用其提供的有状态变体 人们可能会如何安排更多的可能性 一种类型/对象架构。

正如已经指出的那样,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 / Talents函数的推荐资源

此外,我建议阅读我在SO上给出的一些列出的答案,这些答案也与此主题相关。