Skip to content

Commit ef06954

Browse files
committed
加入mixin和trait的介绍
1 parent 6b4181d commit ef06954

File tree

4 files changed

+234
-28
lines changed

4 files changed

+234
-28
lines changed

docs/class.md

Lines changed: 172 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -983,9 +983,9 @@ class Person {
983983
984984
### core-decorators.js
985985
986-
[core-decorators.js](https://github.com/jayphelps/core-decorators.js)提供了几个常见的修饰器。
986+
[core-decorators.js](https://github.com/jayphelps/core-decorators.js)是一个第三方模块,提供了几个常见的修饰器,通过它可以更好地理解修饰器
987987
988-
(1)@autobind
988+
**(1)@autobind**
989989
990990
autobind修饰器使得方法中的this对象,绑定原始对象。
991991
@@ -1006,7 +1006,7 @@ getPerson() === person;
10061006
// true
10071007
```
10081008
1009-
(2)@readonly
1009+
**(2)@readonly**
10101010
10111011
readonly修饰器是的属性或方法不可写。
10121012
@@ -1023,7 +1023,7 @@ dinner.entree = 'salmon';
10231023
// Cannot assign to read only property 'entree' of [object Object]
10241024
```
10251025
1026-
(3)@override
1026+
**(3)@override**
10271027
10281028
override修饰器检查子类的方法,是否正确覆盖了父类的同名方法,如果不正确会报错。
10291029
@@ -1051,7 +1051,7 @@ class Child extends Parent {
10511051
}
10521052
```
10531053
1054-
(4)@deprecate (别名@deprecated)
1054+
**(4)@deprecate (别名@deprecated)**
10551055
10561056
deprecate或deprecated修饰器在控制台显示一条警告,表示该方法将废除。
10571057
@@ -1084,7 +1084,7 @@ person.facepalmHarder();
10841084
//
10851085
```
10861086
1087-
(5)@suppressWarnings
1087+
**(5)@suppressWarnings**
10881088
10891089
suppressWarnings修饰器抑制decorated修饰器导致的`console.warn()`调用。但是,异步代码出发的调用除外。
10901090
@@ -1107,6 +1107,172 @@ person.facepalmWithoutWarning();
11071107
// no warning is logged
11081108
```
11091109
1110+
### Mixin
1111+
1112+
在修饰器的基础上,可以实现Mixin模式。所谓Mixin模式,就是对象继承的一种替代方案,中文译为“混入”(mix in),意为在一个对象之中混入另外一个对象的方法。
1113+
1114+
请看下面的例子。
1115+
1116+
```javascript
1117+
const Foo = {
1118+
foo() { console.log('foo') }
1119+
};
1120+
1121+
class MyClass {}
1122+
1123+
Object.assign(MyClass.prototype, Foo);
1124+
1125+
let obj = new MyClass();
1126+
obj.foo() // 'foo'
1127+
```
1128+
1129+
上面代码之中,对象Foo有一个foo方法,通过`Object.assign`方法,可以将foo方法“混入”MyClass类,导致MyClass的实例obj对象都具有foo方法。这就是“混入”模式的一个简单实现。
1130+
1131+
下面,我们部署一个通用脚本`mixins.js`,将mixin写成一个修饰器。
1132+
1133+
```javascript
1134+
export function mixins(...list) {
1135+
return function (target) {
1136+
Object.assign(target.prototype, ...list);
1137+
};
1138+
}
1139+
```
1140+
1141+
然后,就可以使用上面这个修饰器,为类“混入”各种方法。
1142+
1143+
```javascript
1144+
import { mixins } from './mixins'
1145+
1146+
const Foo = {
1147+
foo() { console.log('foo') }
1148+
};
1149+
1150+
@mixins(Foo)
1151+
class MyClass {}
1152+
1153+
let obj = new MyClass();
1154+
1155+
obj.foo() // "foo"
1156+
```
1157+
1158+
通过mixins这个修饰器,实现了在MyClass类上面“混入”Foo对象的foo方法。
1159+
1160+
### Trait
1161+
1162+
Trait也是一种修饰器,功能与Mixin类型,但是提供更多功能,比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等等。
1163+
1164+
下面采用[traits-decorator](https://github.com/CocktailJS/traits-decorator)这个第三方模块作为例子。这个模块提供的traits修饰器,不仅可以接受对象,还可以接受ES6类作为参数。
1165+
1166+
```javascript
1167+
import {traits } from 'traits-decorator'
1168+
1169+
class TFoo {
1170+
foo() { console.log('foo') }
1171+
}
1172+
1173+
const TBar = {
1174+
bar() { console.log('bar') }
1175+
}
1176+
1177+
@traits(TFoo, TBar)
1178+
class MyClass { }
1179+
1180+
let obj = new MyClass()
1181+
obj.foo() // foo
1182+
obj.bar() // bar
1183+
```
1184+
1185+
上面代码中,通过traits修饰器,在MyClass类上面“混入”了TFoo类的foo方法和TBar对象的bar方法。
1186+
1187+
Trait不允许“混入”同名方法。
1188+
1189+
```javascript
1190+
import {traits } from 'traits-decorator'
1191+
1192+
class TFoo {
1193+
foo() { console.log('foo') }
1194+
}
1195+
1196+
const TBar = {
1197+
bar() { console.log('bar') },
1198+
foo() { console.log('foo') }
1199+
}
1200+
1201+
@traits(TFoo, TBar)
1202+
class MyClass { }
1203+
// 报错
1204+
// throw new Error('Method named: ' + methodName + ' is defined twice.');
1205+
// ^
1206+
// Error: Method named: foo is defined twice.
1207+
```
1208+
1209+
上面代码中,TFoo和TBar都有foo方法,结果traits修饰器报错。
1210+
1211+
一种解决方法是排除TBar的foo方法。
1212+
1213+
```javascript
1214+
import { traits, excludes } from 'traits-decorator'
1215+
1216+
class TFoo {
1217+
foo() { console.log('foo') }
1218+
}
1219+
1220+
const TBar = {
1221+
bar() { console.log('bar') },
1222+
foo() { console.log('foo') }
1223+
}
1224+
1225+
@traits(TFoo, TBar::excludes('foo'))
1226+
class MyClass { }
1227+
1228+
let obj = new MyClass()
1229+
obj.foo() // foo
1230+
obj.bar() // bar
1231+
```
1232+
1233+
上面代码使用绑定运算符(::)在TBar上排除foo方法,混入时就不会报错了。
1234+
1235+
另一种方法是为TBar的foo方法起一个别名。
1236+
1237+
```javascript
1238+
import { traits, alias } from 'traits-decorator'
1239+
1240+
class TFoo {
1241+
foo() { console.log('foo') }
1242+
}
1243+
1244+
const TBar = {
1245+
bar() { console.log('bar') },
1246+
foo() { console.log('foo') }
1247+
}
1248+
1249+
@traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
1250+
class MyClass { }
1251+
1252+
let obj = new MyClass()
1253+
obj.foo() // foo
1254+
obj.aliasFoo() // foo
1255+
obj.bar() // bar
1256+
```
1257+
1258+
上面代码为TBar的foo方法起了别名aliasFoo,于是MyClass也可以混入TBar的foo方法了。
1259+
1260+
alias和excludes方法,可以结合起来使用。
1261+
1262+
```javascript
1263+
@traits(TExample::excludes('foo','bar')::alias({baz:'exampleBaz'}))
1264+
class MyClass {}
1265+
```
1266+
1267+
上面代码排除了TExample的foo方法和bar方法,为baz方法起了别名exampleBaz。
1268+
1269+
as方法则为上面的代码提供了另一种写法。
1270+
1271+
```javascript
1272+
@traits(TExample::as({excludes:['foo', 'bar'], alias: {baz: 'exampleBaz'}}))
1273+
class MyClass {}
1274+
```
1275+
11101276
### Babel转码器的支持
11111277
11121278
目前,Babel转码器已经支持Decorator,命令行的用法如下。

docs/function.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ var f = v => v;
460460

461461
```javascript
462462
var f = function(v) {
463-
return v;
463+
return v;
464464
};
465465
```
466466

@@ -474,7 +474,7 @@ var f = function (){ return 5 };
474474
var sum = (num1, num2) => num1 + num2;
475475
// 等同于
476476
var sum = function(num1, num2) {
477-
return num1 + num2;
477+
return num1 + num2;
478478
};
479479
```
480480

@@ -527,7 +527,7 @@ const square = n => n * n;
527527
```javascript
528528
// 正常函数写法
529529
var result = values.sort(function(a, b) {
530-
return a - b;
530+
return a - b;
531531
});
532532

533533
// 箭头函数写法
@@ -627,6 +627,19 @@ mult2(plus1(5))
627627
// 12
628628
```
629629

630+
箭头函数还有一个功能,就是可以很方便地改写λ演算。
631+
632+
```javascript
633+
// λ演算的写法
634+
fix = λf.(λx.fv.x(x)(v)))(λx.fv.x(x)(v)))
635+
636+
// ES6的写法
637+
var fix = f => (x => f(v => x(x)(v)))
638+
(x => f(v => x(x)(v)));
639+
```
640+
641+
上面两种写法,几乎是一一对应的。由于λ演算对于计算机科学非常重要,这使得我们可以用ES6作为替代工具,探索计算机科学。
642+
630643
## 函数绑定
631644

632645
箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。但是,箭头函数并不适用于所有场合,所以ES7提出了“函数绑定”(function bind)运算符,用来取代call、apply、bind调用。虽然该语法还是ES7的一个提案,但是Babel转码器已经支持。
@@ -647,19 +660,6 @@ i// 等同于
647660
bar.apply(foo, arguments);
648661
```
649662

650-
箭头函数还有一个功能,就是可以很方便地改写λ演算。
651-
652-
```javascript
653-
// λ演算的写法
654-
fix = λf.(λx.fv.x(x)(v)))(λx.fv.x(x)(v)))
655-
656-
// ES6的写法
657-
var fix = f => (x => f(v => x(x)(v)))
658-
(x => f(v => x(x)(v)));
659-
```
660-
661-
上面两种写法,几乎是一一对应的。由于λ演算对于计算机科学非常重要,这使得我们可以用ES6作为替代工具,探索计算机科学。
662-
663663
## 尾调用优化
664664

665665
### 什么是尾调用?

docs/intro.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,21 @@ $ es-checker
120120

121121
## Babel转码器
122122

123-
[Babel](https://babeljs.io/)是一个广泛使用的ES6转码器,可以ES6代码转为ES5代码,从而在浏览器或其他环境执行。这意味着,你可以用ES6的方式编写程序,又不用担心现有环境是否支持。它的安装命令如下。
123+
[Babel](https://babeljs.io/)是一个广泛使用的ES6转码器,可以ES6代码转为ES5代码,从而在浏览器或其他环境执行。这意味着,你可以用ES6的方式编写程序,又不用担心现有环境是否支持。下面是一个例子。
124+
125+
```javascript
126+
// 转码前
127+
input.map(item => item + 1);
128+
129+
// 转码后
130+
input.map(function (item) {
131+
return item + 1;
132+
});
133+
```
134+
135+
上面的原始代码用了箭头函数,这个特性还没有得到广泛支持,Babel将其转为普通函数,就能在现有的JavaScript环境执行了。
136+
137+
它的安装命令如下。
124138

125139
```bash
126140
$ npm install --global babel
@@ -154,10 +168,26 @@ console.log([1, 2, 3].map(function (x) {
154168
}));
155169
```
156170

157-
`-o` 参数将转换后的代码,从标准输出导入文件。
171+
`-o`参数将转换后的代码,从标准输出导入文件。
158172

159173
```bash
160174
$ babel es6.js -o es5.js
175+
# 或者
176+
$ babel es6.js --out-file es5.js
177+
```
178+
179+
`-d`参数用于转换整个目录。
180+
181+
```bash
182+
$ babel -d build-dir source-dir
183+
```
184+
185+
注意,`-d`参数后面跟的是输出目录。
186+
187+
如果希望生成source map文件,则要加上`-s`参数。
188+
189+
```bash
190+
$ babel -d build-dir source-dir -s
161191
```
162192

163193
Babel也可以用于浏览器。
@@ -171,6 +201,12 @@ Babel也可以用于浏览器。
171201

172202
上面代码中,`browser.js`是Babel提供的转换器脚本,可以在浏览器运行。用户的ES6脚本放在script标签之中,但是要注明`type="text/babel"`
173203

204+
Babel配合Browserify一起使用,可以生成浏览器能够直接加载的脚本。
205+
206+
```bash
207+
$ browserify script.js -t babelify --outfile bundle.js
208+
```
209+
174210
## Traceur转码器
175211

176212
Google公司的[Traceur](https://github.com/google/traceur-compiler)转码器,也可以将ES6代码转为ES5代码。

docs/reference.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,17 @@
113113

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

124128
## 工具
125129

0 commit comments

Comments
 (0)