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中类的两个特性:
class能用作表达式或语句,当作为表达式时,它每次赋值时返回一个新的class,有点类似工厂
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实现的。