【问题标题】:ES6: Am I using Classes & Mixins Correctly in JavaScript? [closed]ES6:我在 JavaScript 中正确使用类和 Mixins 吗? [关闭]
【发布时间】:2017-01-02 17:29:24
【问题描述】:

这几天我一直在学习 ECMAScript 6 类、Mixins 和其他特性,但我不确定我对用例的理解是否正确。下面是一个带有类、子类和 Mixins 的示例的 sn-p。

class Person{
    constructor (opts){
        for(let prop of Object.keys(opts)){
            this[prop] = opts[prop];
        }
      Person.count++;
    }

    static count = 0;
}

//Greeting Mixin
const Greetings = Person => class extends Person{
    sayHello(){}
}

//Job Mixin
const Jobs = Person => class extends Person{
    getJobs(){}
    getSalary(){}
    setJobs(){}
    setSalary(){}
}

//Subclass
class WorkingPerson extends Jobs(Greetings(Person)){
    constructor(opts){
        super(opts);
        //this.type = 'nice';
    }

    sayHello(){
        if(this.type == 'nice') 
            console.log(`Hello there! Wonderful day isnt it?`);
        else
            console.log(`Ah! Get out of here!`);
    }

    getJobs(){
        return this.jobs;
    }

    setJobs(...jobs){
        this.jobs.push(jobs);
    }

    getSalary(){
        return this.salary;
    }

    setSalary(salary){
        this.salary = salary;
    }
}

let wp = new WorkingPerson({name:'Ajay',jobs:['Digital Evangelist'],salary:10000});
let wp2 = new WorkingPerson({name:'Ron',jobs:['Entertainer'],salary:20000});
let wp3 = new WorkingPerson({name:'Morris',jobs:['Televangelist'],salary:30000});
console.log(`Number of people = ${Person.count}`);

上面的代码没有错误,我得到了正确的输出。但是,我的 Mixins 实现在语义上是否正确?在给定的上下文中使用 JobsGreetings Mixin 有意义吗?我读了一篇博客Mixins and Javascript: The Good, the Bad, and the Ugly.,其中他们将mixin 定义为抽象子类。查看示例,他们为给定的类添加了一些小功能。由于这听起来与装饰器的定义相似,因此我查看了Python: Use of decorators v/s mixins? 的公认答案的差异。它说:

Mixins 添加了新功能。装饰器用于修改现有的 功能。

这让我想到如果JobsGreetings 是Mixins,那么在这种情况下你会给装饰器举什么例子?如果我有任何错误,请提供正确答案的代码块。

另外,有没有更好的方法来提供输入参数,而不是在实例化 WorkingPerson 时抛出一些原始对象作为参数?

【问题讨论】:

  • 我真的不明白GreetingsJobs 的意义所在。他们只是定义空方法。只需使用class WorkingPerson extends Person
  • 我也是这么想的。但如果你要为 Person 类创建 Mixins,它们会是什么?
  • 我不喜欢 mixins。如果我真的需要多重继承,I would probably use a proxy.
  • @AjayH 该问题不包含需要 mixins 的示例。事实上,类 mixin 在 JS 中并没有那么流行,并且经常表明类设计存在问题。

标签: javascript ecmascript-6


【解决方案1】:

不,mixin 应用不正确。

Person => class extends Person{...}是基本继承,可以相应实现:

class GreetingPerson extends Person {
    sayHello() {...}
}

如果有多个不相关的类应该具有相同的一组方法,请考虑应用composition over inheritance 原则。

对于其余情况(例如,无法根据上述原则重构的多态性)mixin 可以应用于任一原型:

function mixin(obj) {
  return function (target) {
    for (const key of Object.getOwnPropertyNames(obj))
      if (key !== 'constructor')
        target.prototype[key] = obj[key];
    return target;
  }
}

class GreetingBeing {
  sayHello() {...}
}

const Person = mixin(GreetingBeing.prototype)(class Person extends Biped { ... })

// or for ES.Next,
// @mixin(GreetingBeing.prototype)
// class Person extends Biped { ...}

或实例:

class Person extends Biped {
  constructor()
    super();
    Object.assign(this, GreetingBeing.prototype);
  }
}

注意mixin helper/decorator 不做多重继承。它所做的只是将自己的可枚举属性从GreetingBeing.prototype 复制到Person.prototype

【讨论】:

  • 所以这里有一个问题:例如,Scala 中的 mixin,当您检查类型时,您会得到“TheClass with TheMixinClass”(“with”是使用 mixin 功能的关键字)。因此,您可以轻松区分非混合类和混合类。这样的东西在 JS 中是否直接存在?
  • @TimConsolazio 不。该语言不支持 mixins/traits,一个是他/她自己的。在 TypeScript 中,可以在编译时(而不是在运行时)指定与接口的这种关系,例如 @mixin(BazMixin.prototype) class Foo extends Bar implements BazMixin {...。但这可能会导致打字问题,因为由于当前的限制,mixin 并没有得到 TypeScript 本身的喜爱。
  • @samson 这是风格问题。是的,我认为这个默认位置。 const 的目的是防止意外重新分配变量,因此在不打算重新分配的地方使用它是合理的。这样就可以识别发生重新分配的代码,这有时会有所帮助。您看到let 并期望它稍后会被分配。在任何其他情况下,都不清楚let 应该优先于const 的哪个位置。我假设有 JS 风格指南可以用另一种方式解决这个问题。
  • getOwnPropertyNames 也返回constructor。所以mixin函数覆盖了目标对象的构造函数。
  • mixin 函数无法正确复制 getter。一般需要使用getOwnPropertyDescriptordefineProperty
【解决方案2】:

嗯..装饰器还不是提案吗?这里可能是错的,但我认为这可能是未来的状态(哦,我们需要跟上的速度......)

我的理解是:在您的上下文中,假设您希望“工作”是只读的。装饰师可以满足要求。

类似:

function readonly ( target, key, descriptor ) {
    descriptor.writable = false;
    return descriptor;
}

// import the decorator function
import { readonly } from 'my-decorators';

class Person {
  @readonly
  person ( ) { return this.user; }
}

因此,我们在此处将该属性的行为修改为隐式只读,而不是将其隐藏在闭包之类的东西中。我还猜想现在这个属性可以作为“只读”属性进行检查,这样它就可以在 IDE 代码辅助对话框中显示为只读(这很酷)。

Scala 是一种非常好的理解 mixins 的语言。语言本身可能不是你的东西,但 mixins 是该语言中一个重要且广泛使用的部分。无论如何,这就是我获得主要理解的地方,而且它似乎很有效。比直接的 OOP 继承等更不严格、更灵活的概念。

很好的问题,我喜欢探索这些东西。你一定很享受那堂课。

【讨论】:

    猜你喜欢
    • 2012-11-17
    • 2017-07-03
    • 2021-03-15
    • 2013-12-03
    • 2018-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    相关资源
    最近更新 更多