diff --git a/docs/class.md b/docs/class.md index e47a64c..77091f8 100644 --- a/docs/class.md +++ b/docs/class.md @@ -983,9 +983,9 @@ class Person { ### 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对象,绑定原始对象。 @@ -1006,7 +1006,7 @@ getPerson() === person; // true ``` -(2)@readonly +**(2)@readonly** readonly修饰器是的属性或方法不可写。 @@ -1023,7 +1023,7 @@ dinner.entree = 'salmon'; // Cannot assign to read only property 'entree' of [object Object] ``` -(3)@override +**(3)@override** override修饰器检查子类的方法,是否正确覆盖了父类的同名方法,如果不正确会报错。 @@ -1051,7 +1051,7 @@ class Child extends Parent { } ``` -(4)@deprecate (别名@deprecated) +**(4)@deprecate (别名@deprecated)** deprecate或deprecated修饰器在控制台显示一条警告,表示该方法将废除。 @@ -1084,7 +1084,7 @@ person.facepalmHarder(); // ``` -(5)@suppressWarnings +**(5)@suppressWarnings** suppressWarnings修饰器抑制decorated修饰器导致的`console.warn()`调用。但是,异步代码出发的调用除外。 @@ -1107,6 +1107,172 @@ person.facepalmWithoutWarning(); // 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转码器已经支持Decorator,命令行的用法如下。 diff --git a/docs/function.md b/docs/function.md index 6674c89..0c35f8c 100644 --- a/docs/function.md +++ b/docs/function.md @@ -460,7 +460,7 @@ var f = v => v; ```javascript var f = function(v) { - return v; + return v; }; ``` @@ -474,7 +474,7 @@ var f = function (){ return 5 }; var sum = (num1, num2) => num1 + num2; // 等同于 var sum = function(num1, num2) { - return num1 + num2; + return num1 + num2; }; ``` @@ -527,7 +527,7 @@ const square = n => n * n; ```javascript // 正常函数写法 var result = values.sort(function(a, b) { - return a - b; + return a - b; }); // 箭头函数写法 @@ -627,6 +627,19 @@ mult2(plus1(5)) // 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转码器已经支持。 @@ -647,19 +660,6 @@ i// 等同于 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作为替代工具,探索计算机科学。 - ## 尾调用优化 ### 什么是尾调用? diff --git a/docs/intro.md b/docs/intro.md index 8860d81..f5f90d6 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -120,7 +120,21 @@ $ es-checker ## 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 $ npm install --global babel @@ -154,10 +168,26 @@ console.log([1, 2, 3].map(function (x) { })); ``` -`-o` 参数将转换后的代码,从标准输出导入文件。 +`-o`参数将转换后的代码,从标准输出导入文件。 ```bash $ 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也可以用于浏览器。 @@ -171,6 +201,12 @@ Babel也可以用于浏览器。 上面代码中,`browser.js`是Babel提供的转换器脚本,可以在浏览器运行。用户的ES6脚本放在script标签之中,但是要注明`type="text/babel"`。 +Babel配合Browserify一起使用,可以生成浏览器能够直接加载的脚本。 + +```bash +$ browserify script.js -t babelify --outfile bundle.js +``` + ## Traceur转码器 Google公司的[Traceur](https://github.com/google/traceur-compiler)转码器,也可以将ES6代码转为ES5代码。 diff --git a/docs/reference.md b/docs/reference.md index a630f77..0ce5bc4 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -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的写法对比 - 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模块入门 - 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模块的静态化设计思想 -- 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的深入介绍 ## 工具