1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

加入mixin和trait的介绍

This commit is contained in:
Ruan Yifeng 2015-07-20 16:24:50 +08:00
parent 6b4181d329
commit ef0695403f
4 changed files with 234 additions and 28 deletions

View File

@ -983,9 +983,9 @@ class Person {
### core-decorators.js ### core-decorators.js
[core-decorators.js](https://github.com/jayphelps/core-decorators.js)提供了几个常见的修饰器。 [core-decorators.js](https://github.com/jayphelps/core-decorators.js)是一个第三方模块,提供了几个常见的修饰器,通过它可以更好地理解修饰器。
1@autobind **1@autobind**
autobind修饰器使得方法中的this对象绑定原始对象。 autobind修饰器使得方法中的this对象绑定原始对象。
@ -1006,7 +1006,7 @@ getPerson() === person;
// true // true
``` ```
2@readonly **2@readonly**
readonly修饰器是的属性或方法不可写。 readonly修饰器是的属性或方法不可写。
@ -1023,7 +1023,7 @@ dinner.entree = 'salmon';
// Cannot assign to read only property 'entree' of [object Object] // Cannot assign to read only property 'entree' of [object Object]
``` ```
3@override **3@override**
override修饰器检查子类的方法是否正确覆盖了父类的同名方法如果不正确会报错。 override修饰器检查子类的方法是否正确覆盖了父类的同名方法如果不正确会报错。
@ -1051,7 +1051,7 @@ class Child extends Parent {
} }
``` ```
4@deprecate (别名@deprecated) **4@deprecate (别名@deprecated)**
deprecate或deprecated修饰器在控制台显示一条警告表示该方法将废除。 deprecate或deprecated修饰器在控制台显示一条警告表示该方法将废除。
@ -1084,7 +1084,7 @@ person.facepalmHarder();
// //
``` ```
5@suppressWarnings **5@suppressWarnings**
suppressWarnings修饰器抑制decorated修饰器导致的`console.warn()`调用。但是,异步代码出发的调用除外。 suppressWarnings修饰器抑制decorated修饰器导致的`console.warn()`调用。但是,异步代码出发的调用除外。
@ -1107,6 +1107,172 @@ person.facepalmWithoutWarning();
// no warning is logged // no warning is logged
``` ```
### Mixin
在修饰器的基础上可以实现Mixin模式。所谓Mixin模式就是对象继承的一种替代方案中文译为“混入”mix in意为在一个对象之中混入另外一个对象的方法。
请看下面的例子。
```javascript
const Foo = {
foo() { console.log('foo') }
};
class MyClass {}
Object.assign(MyClass.prototype, Foo);
let obj = new MyClass();
obj.foo() // 'foo'
```
上面代码之中对象Foo有一个foo方法通过`Object.assign`方法可以将foo方法“混入”MyClass类导致MyClass的实例obj对象都具有foo方法。这就是“混入”模式的一个简单实现。
下面,我们部署一个通用脚本`mixins.js`将mixin写成一个修饰器。
```javascript
export function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list);
};
}
```
然后,就可以使用上面这个修饰器,为类“混入”各种方法。
```javascript
import { mixins } from './mixins'
const Foo = {
foo() { console.log('foo') }
};
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // "foo"
```
通过mixins这个修饰器实现了在MyClass类上面“混入”Foo对象的foo方法。
### Trait
Trait也是一种修饰器功能与Mixin类型但是提供更多功能比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等等。
下面采用[traits-decorator](https://github.com/CocktailJS/traits-decorator)这个第三方模块作为例子。这个模块提供的traits修饰器不仅可以接受对象还可以接受ES6类作为参数。
```javascript
import {traits } from 'traits-decorator'
class TFoo {
foo() { console.log('foo') }
}
const TBar = {
bar() { console.log('bar') }
}
@traits(TFoo, TBar)
class MyClass { }
let obj = new MyClass()
obj.foo() // foo
obj.bar() // bar
```
上面代码中通过traits修饰器在MyClass类上面“混入”了TFoo类的foo方法和TBar对象的bar方法。
Trait不允许“混入”同名方法。
```javascript
import {traits } from 'traits-decorator'
class TFoo {
foo() { console.log('foo') }
}
const TBar = {
bar() { console.log('bar') },
foo() { console.log('foo') }
}
@traits(TFoo, TBar)
class MyClass { }
// 报错
// throw new Error('Method named: ' + methodName + ' is defined twice.');
// ^
// Error: Method named: foo is defined twice.
```
上面代码中TFoo和TBar都有foo方法结果traits修饰器报错。
一种解决方法是排除TBar的foo方法。
```javascript
import { traits, excludes } from 'traits-decorator'
class TFoo {
foo() { console.log('foo') }
}
const TBar = {
bar() { console.log('bar') },
foo() { console.log('foo') }
}
@traits(TFoo, TBar::excludes('foo'))
class MyClass { }
let obj = new MyClass()
obj.foo() // foo
obj.bar() // bar
```
上面代码使用绑定运算符(::在TBar上排除foo方法混入时就不会报错了。
另一种方法是为TBar的foo方法起一个别名。
```javascript
import { traits, alias } from 'traits-decorator'
class TFoo {
foo() { console.log('foo') }
}
const TBar = {
bar() { console.log('bar') },
foo() { console.log('foo') }
}
@traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
class MyClass { }
let obj = new MyClass()
obj.foo() // foo
obj.aliasFoo() // foo
obj.bar() // bar
```
上面代码为TBar的foo方法起了别名aliasFoo于是MyClass也可以混入TBar的foo方法了。
alias和excludes方法可以结合起来使用。
```javascript
@traits(TExample::excludes('foo','bar')::alias({baz:'exampleBaz'}))
class MyClass {}
```
上面代码排除了TExample的foo方法和bar方法为baz方法起了别名exampleBaz。
as方法则为上面的代码提供了另一种写法。
```javascript
@traits(TExample::as({excludes:['foo', 'bar'], alias: {baz: 'exampleBaz'}}))
class MyClass {}
```
### Babel转码器的支持 ### Babel转码器的支持
目前Babel转码器已经支持Decorator命令行的用法如下。 目前Babel转码器已经支持Decorator命令行的用法如下。

View File

@ -627,6 +627,19 @@ mult2(plus1(5))
// 12 // 12
``` ```
箭头函数还有一个功能,就是可以很方便地改写λ演算。
```javascript
// λ演算的写法
fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v)))
// ES6的写法
var fix = f => (x => f(v => x(x)(v)))
(x => f(v => x(x)(v)));
```
上面两种写法几乎是一一对应的。由于λ演算对于计算机科学非常重要这使得我们可以用ES6作为替代工具探索计算机科学。
## 函数绑定 ## 函数绑定
箭头函数可以绑定this对象大大减少了显式绑定this对象的写法call、apply、bind。但是箭头函数并不适用于所有场合所以ES7提出了“函数绑定”function bind运算符用来取代call、apply、bind调用。虽然该语法还是ES7的一个提案但是Babel转码器已经支持。 箭头函数可以绑定this对象大大减少了显式绑定this对象的写法call、apply、bind。但是箭头函数并不适用于所有场合所以ES7提出了“函数绑定”function bind运算符用来取代call、apply、bind调用。虽然该语法还是ES7的一个提案但是Babel转码器已经支持。
@ -647,19 +660,6 @@ i// 等同于
bar.apply(foo, arguments); bar.apply(foo, arguments);
``` ```
箭头函数还有一个功能,就是可以很方便地改写λ演算。
```javascript
// λ演算的写法
fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v)))
// ES6的写法
var fix = f => (x => f(v => x(x)(v)))
(x => f(v => x(x)(v)));
```
上面两种写法几乎是一一对应的。由于λ演算对于计算机科学非常重要这使得我们可以用ES6作为替代工具探索计算机科学。
## 尾调用优化 ## 尾调用优化
### 什么是尾调用? ### 什么是尾调用?

View File

@ -120,7 +120,21 @@ $ es-checker
## Babel转码器 ## Babel转码器
[Babel](https://babeljs.io/)是一个广泛使用的ES6转码器可以ES6代码转为ES5代码从而在浏览器或其他环境执行。这意味着你可以用ES6的方式编写程序又不用担心现有环境是否支持。它的安装命令如下。 [Babel](https://babeljs.io/)是一个广泛使用的ES6转码器可以ES6代码转为ES5代码从而在浏览器或其他环境执行。这意味着你可以用ES6的方式编写程序又不用担心现有环境是否支持。下面是一个例子。
```javascript
// 转码前
input.map(item => item + 1);
// 转码后
input.map(function (item) {
return item + 1;
});
```
上面的原始代码用了箭头函数这个特性还没有得到广泛支持Babel将其转为普通函数就能在现有的JavaScript环境执行了。
它的安装命令如下。
```bash ```bash
$ npm install --global babel $ npm install --global babel
@ -154,10 +168,26 @@ console.log([1, 2, 3].map(function (x) {
})); }));
``` ```
`-o` 参数将转换后的代码,从标准输出导入文件。 `-o`参数将转换后的代码,从标准输出导入文件。
```bash ```bash
$ babel es6.js -o es5.js $ babel es6.js -o es5.js
# 或者
$ babel es6.js --out-file es5.js
```
`-d`参数用于转换整个目录。
```bash
$ babel -d build-dir source-dir
```
注意,`-d`参数后面跟的是输出目录。
如果希望生成source map文件则要加上`-s`参数。
```bash
$ babel -d build-dir source-dir -s
``` ```
Babel也可以用于浏览器。 Babel也可以用于浏览器。
@ -171,6 +201,12 @@ Babel也可以用于浏览器。
上面代码中,`browser.js`是Babel提供的转换器脚本可以在浏览器运行。用户的ES6脚本放在script标签之中但是要注明`type="text/babel"` 上面代码中,`browser.js`是Babel提供的转换器脚本可以在浏览器运行。用户的ES6脚本放在script标签之中但是要注明`type="text/babel"`
Babel配合Browserify一起使用可以生成浏览器能够直接加载的脚本。
```bash
$ browserify script.js -t babelify --outfile bundle.js
```
## Traceur转码器 ## Traceur转码器
Google公司的[Traceur](https://github.com/google/traceur-compiler)转码器也可以将ES6代码转为ES5代码。 Google公司的[Traceur](https://github.com/google/traceur-compiler)转码器也可以将ES6代码转为ES5代码。

View File

@ -113,13 +113,17 @@
- Sebastian Porto, [ES6 classes and JavaScript prototypes](https://reinteractive.net/posts/235-es6-classes-and-javascript-prototypes): ES6 Class的写法与ES5 Prototype的写法对比 - Sebastian Porto, [ES6 classes and JavaScript prototypes](https://reinteractive.net/posts/235-es6-classes-and-javascript-prototypes): ES6 Class的写法与ES5 Prototype的写法对比
- Jack Franklin, [An introduction to ES6 classes](http://javascriptplayground.com/blog/2014/07/introduction-to-es6-classes-tutorial/): ES6 class的入门介绍 - Jack Franklin, [An introduction to ES6 classes](http://javascriptplayground.com/blog/2014/07/introduction-to-es6-classes-tutorial/): ES6 class的入门介绍
- Axel Rauschmayer, [ECMAScript 6: new OOP features besides classes](http://www.2ality.com/2014/12/es6-oop.html)
- Axel Rauschmayer, [Classes in ECMAScript 6 (final semantics)](http://www.2ality.com/2015/02/es6-classes-final.html): Class语法的详细介绍和设计思想分析
- Maximiliano Fierro, [Declarative vs Imperative](http://elmasse.github.io/js/decorators-bindings-es7.html): Decorators和Mixin介绍
- Addy Osmani, [Exploring ES2016 Decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841): Decorator的深入介绍
- Maximiliano Fierro, [Traits with ES7 Decorators](http://cocktailjs.github.io/blog/traits-with-es7-decorators.html): Trait的用法介绍
## 模块
- Jack Franklin, [JavaScript Modules the ES6 Way](http://24ways.org/2014/javascript-modules-the-es6-way/): ES6模块入门 - Jack Franklin, [JavaScript Modules the ES6 Way](http://24ways.org/2014/javascript-modules-the-es6-way/): ES6模块入门
- Axel Rauschmayer, [ECMAScript 6 modules: the final syntax](http://www.2ality.com/2014/09/es6-modules-final.html): ES6模块的介绍以及与CommonJS规格的详细比较 - Axel Rauschmayer, [ECMAScript 6 modules: the final syntax](http://www.2ality.com/2014/09/es6-modules-final.html): ES6模块的介绍以及与CommonJS规格的详细比较
- Dave Herman, [Static module resolution](http://calculist.org/blog/2012/06/29/static-module-resolution/): ES6模块的静态化设计思想 - Dave Herman, [Static module resolution](http://calculist.org/blog/2012/06/29/static-module-resolution/): ES6模块的静态化设计思想
- Axel Rauschmayer, [ECMAScript 6: new OOP features besides classes](http://www.2ality.com/2014/12/es6-oop.html)
- Axel Rauschmayer, [Classes in ECMAScript 6 (final semantics)](http://www.2ality.com/2015/02/es6-classes-final.html): Class语法的详细介绍和设计思想分析
- Maximiliano Fierro, [Declarative vs Imperative](http://elmasse.github.io/js/decorators-bindings-es7.html): Decorators介绍
- Addy Osmani, [Exploring ES2016 Decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841): Decorator的深入介绍
## 工具 ## 工具