如何向 ES6 javascript 类添加 mixins?

Posted

技术标签:

【中文标题】如何向 ES6 javascript 类添加 mixins?【英文标题】:How to add mixins to ES6 javascript classes? 【发布时间】: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 功能。

【问题讨论】:

【参考方案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 类只是隐藏了良好的原型继承的语法糖。所以它们基本上都是经过修饰的构造函数。 相关***.com/questions/46795498/…

以上是关于如何向 ES6 javascript 类添加 mixins?的主要内容,如果未能解决你的问题,请参考以下文章

向ES6看齐,用更好的JavaScript

javascript:仅当父元素处于活动状态且子元素具有特定类时,如何向子元素添加属性?

如何克隆 javascript ES6 类实例

如何使用 ES6 样式导入添加外部 javascript 库?

ts介绍

如何从 ES6 JavaScript 类实例中获取源代码位置?