Javascript如何实现类的Mixin混合?

  Mixin功能是类似接口的一种子类,这种子类能够像实现多个接口一样实现多个超类功能。一个Mixin分两个部分:

1.Mixin定义,一个类的定义可以应用到不同超类,实际是一个子类工厂,

2.Mixin应用,将Mixin定义应用到一个超类,超类能产生新的子类。

下面是一个通过函数实现Mixin的代码,其实则是将源类中属性改写到目标类属性中:

function mixin(source, target) {
  for (var prop in source) {
    if (source.hasOwnProperty(prop)) {
      target[prop] = source[prop];
    }
  }
}

当我们使用:

mixin(MyMixin, MyClass.prototype);

MyClass 就有了MyMixin的所有属性了。

现在我们看看Javascript6/es6中类的两个特性:

  1. class能用作表达式或语句,当作为表达式时,它每次赋值时返回一个新的class,有点类似工厂
  2. extends能够接受任何返回类或构造器的表达式。注意这里extends很特殊,它后面不是一个固定的标识(不同于Java等语言里面extends),extends 后面可以是任意表达式。

我们看看ES6中继承extends实现如下:

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

然后,我们就可以在extends中使用MyMixin:

class MyClass extends MyMixin(MyBaseClass) {  
  /* ... */ 
} 

这样,MyClass通过Mixin继承有了foo的方法:

let c = new MyClass();
c.foo(); // prints "foo from MyMixin"

更复杂的一个Mixin代码:

let Mixin1 = (superclass) => class extends superclass {  
  foo() { 
    console.log('foo from Mixin1'); 
    if (super.foo) super.foo(); 
  } 
}; 
let Mixin2 = (superclass) => class extends superclass {  
  foo() { 
    console.log('foo from Mixin2'); 
    if (super.foo) super.foo(); 
  } 
}; 
class S {  
  foo() { 
    console.log('foo from S'); 
  } 
} 
class C extends Mixin1(Mixin2(S)) {  
  foo() { 
    console.log('foo from C'); 
    super.foo(); 
  } 
} 
new C().foo();   

输出结果:

foo from C
foo from Mixin1
foo from Mixin2
foo from S

再看看另外一个案例:

const Storage = Sup => class extends Sup { 
    save(database) { ··· } 
}; 
const Validation = Sup => class extends Sup { 
    validate(schema) { ··· } 
}; 

那么我们混合这两种Mixin类的新类如下:

class Employee extends Storage(Validation(Person)) { ··· }

总之,Mixin主要使用了Javascript的特殊强大的extends实现的。

Javascript技巧与模式

Javascript专题