大家知道,将ES6代码编译为ES5时,我们常用到Babel这个编译工具。大家参考一些网上的文章或者官方文档,里面常会建议大家在.babelrc中输入如下代码:
1{ 2 "presets": [ 3 "es2015", 4 "react", 5 "stage-0" 6 ], 7 "plugins": [] 8 }
babel 总共分为三个阶段:解析,转换,生成。 我们需要知道现在 babel 本身是不具备这种转化功能,提供这些转化功能的是一个个 plugin。所以我们没有配置任何 plugin 的时候,经过 Babel 输出的代码是没有改变的 下面我们来了解一下Babel中的stage-0、stage-1、stage-2、stage-3ji及它们支持的一些插件
1. 法力无边的stage-0
为什么说“stage-0” 法力无边呢,因为它包含stage-1, stage-2以及stage-3的所有功能,同时还另外支持如下两个功能插件:
1transform-do-expressions 2transform-function-bind
用过React的同学可能知道,jsx对条件表达式支持的不是太好,你不能很方便的使用if/else表达式,要么你使用三元表达,要么用函数。例如你不能写如下的代码:
1var App = React.createClass({ 2 3 render(){ 4 let { color } = this.props; 5 6 return ( 7 <div className="parents"> 8 { 9 if(color == 'blue') { 10 <BlueComponent/>; 11 }else if(color == 'red') { 12 <RedComponent/>; 13 }else { 14 <GreenComponent/>; } 15 } 16 } 17 </div> 18 ) 19 } 20})
在React中你只能写成这样:
1var App = React.createClass({ 2 3 render(){ 4 let { color } = this.props; 5 6 7 const getColoredComponent = color => { 8 if(color === 'blue') { return <BlueComponent/>; } 9 if(color === 'red') { return <RedComponent/>; } 10 if(color === 'green') { return <GreenComponent/>; } 11 } 12 13 14 return ( 15 <div className="parents"> 16 { getColoredComponent(color) } 17 </div> 18 ) 19 } 20})
transform-do-expressions 这个插件就是为了方便在 jsx写if/else表达式而提出的,我们可以重写下代码。
1var App = React.createClass({ 2 3 render(){ 4 let { color } = this.props; 5 6 return ( 7 <div className="parents"> 8 {do { 9 if(color == 'blue') { 10 <BlueComponent/>; 11 }else if(color == 'red') { 12 <RedComponent/>; 13 }else { 14 <GreenComponent/>; } 15 } 16 }} 17 </div> 18 ) 19 } 20})
再说说 transform-function-bind, 这个插件其实就是提供过 :: 这个操作符来方便快速切换上下文, 如下面的代码:
1obj::func 2// is equivalent to: 3func.bind(obj) 4 5obj::func(val) 6// is equivalent to: 7func.call(obj, val) 8 9::obj.func(val) 10// is equivalent to: 11func.call(obj, val) 12 13// 再来一个复杂点的样例 14 15const box = { 16 weight: 2, 17 getWeight() { return this.weight; }, 18}; 19 20const { getWeight } = box; 21 22console.log(box.getWeight()); // prints '2' 23 24const bigBox = { weight: 10 }; 25console.log(bigBox::getWeight()); // prints '10' 26 27// Can be chained: 28function add(val) { return this + val; } 29 30console.log(bigBox::getWeight()::add(5)); // prints '15'
2. 包罗万象的stage-1
stage-1除了包含stage-2和stage-3,还包含了下面4个插件:
1transform-class-constructor-call (Deprecated) 2transform-class-properties 3transform-decorators – disabled pending proposal update 4transform-export-extensions
3. 深藏不露的stage-2
为什么说 stage-2深藏不露呢,因为它很低调,低调到你可以忽略它,但事实上,它很有内涵的。它除了覆盖stage-3的所有功能,还支持如下两个插件:
1syntax-trailing-function-commas 2transform-object-reset-spread
syntax-trailing-function-commas这个插件它不是对ES6功能的增加,而是为了增强代码的可读性和可修改性而提出的
1// 假设有如下的一个函数,它有两个参数 2function clownPuppiesEverywhere( 3 param1, 4 param2 5) { /* ... */ } 6 7clownPuppiesEverywhere( 8 'foo', 9 'bar' 10); 11 12// 有一天,它需要变成3个参数,你需要这样修改 13function clownPuppiesEverywhere( 14 param1, 15- param2 16+ param2, // 这一行得加一个逗号 17+ param3 // 增加参数param3 18) { /* ... */ } 19 20clownPuppiesEverywhere( 21 'foo', 22- 'bar' 23+ 'bar', // 这里的修改为逗号 24+ 'baz' // 增加新的参数 25);
// 我们来重新定义一下函数
1function clownPuppiesEverywhere( 2 param1, 3 param2, // 注意这里,我们加了一个逗号哟 4) { /* ... */ } 5 6clownPuppiesEverywhere( 7 'foo', 8 'bar', // 这里我们也加了一个逗号 9); 10 11// 现在函数需要三个参数,我们来修改下 12function clownPuppiesEverywhere( 13 param1, 14 param2, 15+ param3, // 增加params3参数 16) { /* ... */ }
stage-2中的syntax-trailing-function-commas就是有"尾逗号函数”功能
transform-object-rest-spread 再来说transform-object-rest-spread, 其实它是对 ES6中解构赋值的一个扩展,因为ES6只支持对数组的解构赋值,对对象是不支持的。如下面的代码所示:
// 获取剩下的属性
1let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; 2console.log(x); // 1 3console.log(y); // 2 4console.log(z); // { a: 3, b: 4 } 5 6// 属性展开 7let n = { x, y, ...z }; 8console.log(n); // { x: 1, y: 2, a: 3, b: 4 }
4. 深藏不露的stage-3
为啥说stage3大放异彩呢?因为它支持大名鼎鼎的async和await, 这两个哥们可是解决(Ajax)回调函数的终极解决方法呀!管你什么异步,我都可以用同步的思维来写,ES7里面非常强悍的存在。总的来说,它包含如下两个插件:
1transform-async-to-generator 2transform-exponentiation-operator
transform-async-to-generator主要用来支持ES7中的async和await 提示: 由于asycn和await是ES7里面的内容,现阶段不建议使用。为了顺利运行上面的代码,建议用webpack进行编译。 transform-exponentiation-operator transform-exponentiation-operator这个插件算是一个语法糖,可以通过**这个符号来进行幂操作,想当于Math.pow(a,b)。如下面的样例
1// x ** y 2 3let squared = 2 ** 2; 4// 相当于: 2 * 2 5 6let cubed = 2 ** 3; 7// 相当于: 2 * 2 * 2 8 9 10// x **= y 11 12let a = 2; 13a **= 2; 14// 相当于: a = a * a; 15 16let b = 3; 17b **= 3; 18// 相当于: b = b * b * b;
结语:在进行实际开发时,可以更具需要来设置对应的stage。如果省事懒得折腾,一般设置为stage-0即可。如果为了防止开发人员使用某些太新的功能,我们可以限制到某个特定的stage即可