diff --git a/docs/decorator.md b/docs/decorator.md index 127ef5b..bdcfec5 100644 --- a/docs/decorator.md +++ b/docs/decorator.md @@ -423,7 +423,7 @@ let obj = new MyClass(); obj.foo() // 'foo' ``` -上面代码之中,对象Foo有一个foo方法,通过`Object.assign`方法,可以将foo方法“混入”MyClass类,导致MyClass的实例obj对象都具有foo方法。这就是“混入”模式的一个简单实现。 +上面代码之中,对象`Foo`有一个`foo`方法,通过`Object.assign`方法,可以将`foo`方法“混入”`MyClass`类,导致`MyClass`的实例`obj`对象都具有`foo`方法。这就是“混入”模式的一个简单实现。 下面,我们部署一个通用脚本`mixins.js`,将mixin写成一个修饰器。 @@ -453,6 +453,86 @@ obj.foo() // "foo" 通过mixins这个修饰器,实现了在MyClass类上面“混入”Foo对象的`foo`方法。 +不过,上面的方法会改写`MyClass`类的`prototype`对象,如果不喜欢这一点,也可以通过类的继承实现mixin。 + +```javascript +class MyClass extends MyBaseClass { + /* ... */ +} +``` + +上面代码中,`MyClass`继承了`MyBaseClass`。如果我们想在`MyClass`里面“混入”一个`foo`方法,一个办法是在`MyClass`和`MyBaseClass`之间插入一个混入类,这个类具有`foo`方法,并且继承了`MyBaseClass`的所有方法,然后`MyClass`再继承这个类。 + +```javascript +let MyMixin = (superclass) => class extends superclass { + foo() { + console.log('foo from MyMixin'); + } +}; +``` + +上面代码中,`MyMixin`是一个混入类生成器,接受`superclass`作为参数,然后返回一个继承`superclass`的子类,该子类包含一个`foo`方法。 + +接着,目标类再去继承这个混入类,就达到了“混入”`foo`方法的目的。 + +```javascript +class MyClass extends MyMixin(MyBaseClass) { + /* ... */ +} + +let c = new MyClass(); +c.foo(); // "foo from MyMixin" +``` + +如果需要“混入”多个方法,就生成多个混入类。 + +```javascript +class MyClass extends Mixin1(Mixin2(MyBaseClass)) { + /* ... */ +} +``` + +这种写法的一个好处,是可以调用`super`,因此可以避免在“混入”过程中覆盖父类的同名方法。 + +```javascript +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(); + } +} +``` + +上面代码中,每一次`混入`发生时,都调用了父类的`super.foo`方法,导致父类的同名方法没有被覆盖,行为被保留了下来。 + +```javascript +new C().foo() +// foo from C +// foo from Mixin1 +// foo from Mixin2 +// foo from S +``` + ## Trait Trait也是一种修饰器,效果与Mixin类似,但是提供更多功能,比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等等。 diff --git a/docs/reference.md b/docs/reference.md index 3218e9a..468ff44 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -173,6 +173,7 @@ ## Decorator - Maximiliano Fierro, [Declarative vs Imperative](http://elmasse.github.io/js/decorators-bindings-es7.html): Decorators和Mixin介绍 +- Justin Fagnani, ["Real" Mixins with JavaScript Classes](http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/): 使用类的继承实现Mixin - Addy Osmani, [Exploring ES2016 Decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841): Decorator的深入介绍 - Sebastian McKenzie, [Allow decorators for functions as well](https://github.com/wycats/javascript-decorators/issues/4): 为什么修饰器不能用于函数 - Maximiliano Fierro, [Traits with ES7 Decorators](http://cocktailjs.github.io/blog/traits-with-es7-decorators.html): Trait的用法介绍