【问题标题】:How to add mixins to ES6 javascript classes?如何向 ES6 javascript 类添加 mixins?
【发布时间】:2017-07-03 23:58:41
【问题描述】:

在带有一些实例变量和方法的 ES6 类中,如何向其中添加 mixin?我在下面给出了一个例子,虽然我不知道 mixin 对象的语法是否正确。

class Test {
  constructor() {
    this.var1 = 'var1'
  }
  method1() {
    console.log(this.var1)
  }
  test() {
    this.method2()
  }
}

var mixin = {
  var2: 'var2',
  method2: {
    console.log(this.var2)
  }
}

如果我运行(new Test()).test(),它将失败,因为类上没有method2,因为它在mixin中,这就是为什么我需要将mixin变量和方法添加到类中。

我看到有一个 lodash mixin 函数https://lodash.com/docs/4.17.4#mixin,但我不知道如何将它与 ES6 类一起使用。我可以使用 lodash 作为解决方案,甚至可以使用没有库的普通 JS 来提供 mixin 功能。

【问题讨论】:

    标签: javascript node.js class ecmascript-6 lodash


    【解决方案1】:

    Javascript 的对象/属性系统比大多数语言动态得多,因此向对象添加功能非常容易。由于函数是一等对象,它们可以以完全相同的方式添加到对象中。 Object.assign 是将一个对象的属性添加到另一个对象的方法。 (它的行为在很多方面都可以与_.mixin 媲美。)

    Javascript 中的类只是使添加构造函数/原型对变得简单明了的语法糖。该功能与 ES6 之前的代码相比没有变化。

    您可以将属性添加到原型中:

    Object.assign(Test.prototype, mixin);
    

    您可以在构造函数中将它添加到创建的每个对象:

    constructor() {
        this.var1 = 'var1';
        Object.assign(this, mixin);
    }
    

    您可以根据条件将其添加到构造函数中:

    constructor() {
        this.var1 = 'var1';
        if (someCondition) {
            Object.assign(this, mixin);
        }
    }
    

    或者您可以在创建对象后将其分配给对象:

    let test = new Test();
    Object.assign(test, mixin);
    

    【讨论】:

    • @lonesomeday 将它添加到对象本身的原型有什么区别?我认为在声明方法时最好在原型上进行,因为这样所有对象都共享相同的功能,而不是它们都有自己的功能来做同样的事情。这是否也适用于这种混合技术,将其应用于原型比对象更有效?
    • @user779159 该函数只会存在一次。只有当您再次声明该函数时,才会创建第二个函数。 (例如,如果你有一个装饰器函数,它每次运行时都会创建一个新函数。)
    • @lonesomeday 出于兴趣,如果 mixin 是在与 Object 不同的文件中声明的,那会是什么样子。就像 mixin 文件上的导出和目标文件(或声明对象的位置)上的要求一样
    • 如果这显示了如何做一个混合,你正在混合的东西是一个 ES6 类本身(例如,目标和源都是 ES6 类)。在我看来,Object.assign() 对此不起作用,可能是因为 ES6 方法默认情况下不可迭代。
    【解决方案2】:

    在 es6 中,您可以在不分配的情况下执行此操作,甚至可以在正确的时间调用 mixin 构造函数!

    http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/#bettermixinsthroughclassexpressions

    此模式使用class expressions 为每个mixin 创建一个新的基类。

    let MyMixin = (superclass) => class extends superclass {
      foo() {
        console.log('foo from MyMixin');
      }
    };
    
    class MyClass extends MyMixin(MyBaseClass) {
      /* ... */
    }
    

    【讨论】:

    • 很遗憾,该文章提供了虚假信息。他说 MixIn 提供了对“instanceOf()”的肯定;这是不正确的。同样的误解是他整个技术的基础。他正在加长继承链。 MixIns从水平方向加入一个Class,但他是在垂直延伸继承链。
    • 我认为扩展继承链是更好的方法。 instanceof 只是一个附带好处,并且需要一些花哨的步法。 Otoh 使用这种方法,您可以以受控方式运行构造函数逻辑,这是主要好处。
    • 继承和混入是两种不同的操作。在大多数语言中(那些不知道如何解决diamond problem 的人),您只能从一个超类继承。但是在每种语言中,您都可以根据需要混合任意数量的课程。
    • 任何一种方式都是定义语言特性的完美有效方式,允许您向许多类添加通用功能,并且文章非常清楚地提供了哪些语义,因此没有混淆的危险.此外,语义与 ruby​​ 中称为 mixins 的模块包含并没有真正的不同(在这里,当您包含一个模块时,您会覆盖其他模块中通常调用的方法)。
    【解决方案3】:

    你应该看看Object.assign()。看起来应该是这样的:

    Object.assign(Test.prototype, mixin);
    

    这将确保来自mixin 的所有方法和属性都将被复制到Test 构造函数的原型对象中。

    【讨论】:

    • 有没有办法从class 本身调用它?
    • 这是非常值得怀疑的。这是因为 ES6 类只是隐藏了良好的原型继承的语法糖。所以它们基本上都是经过修饰的构造函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 2021-07-19
    • 1970-01-01
    • 2016-03-22
    • 2016-09-26
    • 2017-12-27
    • 2016-11-16
    相关资源
    最近更新 更多