babel の preset-stage-n の内訳

babel の plugin の中に preset-stage-0, preset-stage-1, preset-stage-2, preset-stage-3 というのがあって「入れとくと未来の機能が使えそう。便利」という感じで使うと死にそうなので、中身が何なのか調べたメモ。
結論としては、preset-stage-n という形で入れるのではなくて、欲しい機能の preset を明示的に指定するのが良さそう。

# preset-stage-0

- http://babeljs.io/docs/plugins/preset-stage-0

## transform-do-expressions

- http://babeljs.io/docs/plugins/transform-do-expressions
- 最後に評価された結果の値が返るブロック

```js
let b = do {
    let a = 1;
    a++;
    a;
}; //=> 2
```

## transform-function-bind

- http://babeljs.io/docs/plugins/transform-function-bind
- 外から持ってきた関数を使ってメソッドチェインみたいに使う事ができるようになる
- call のネストをしなくて済むのが嬉しい

```js
let a = [1,2,3];
let map = Array.prototype.map;
let forEach = Array.prototype.forEach;

// ES6 まではこうやってた
forEach.call(map.call(a, (n) => n * 2), (n) => console.log(n));
// 2
// 4
// 6

// Function Bind Syntax を使うとメソッドチェインっぽくできる
a::map((n) => n * 2)::forEach((n) => console.log(n));
// 2
// 4
// 6
```

# preset-stage-1

- http://babeljs.io/docs/plugins/preset-stage-1/

## transform-class-constructor-call

- http://babeljs.io/docs/plugins/transform-class-constructor-call/
- new 無しでコンストラクタが呼ばれたときの関数を別途定義できる

```js
class Hoge {
    constructor() {
        this.n = 99;
    }

    call constructor() {
        return 100;
    }
}

new Hoge().n; //=> 99
Hoge(); //=> 100
```

### 追記

- (Deprecated)になってる

## transform-export-extensions

- http://babeljs.io/docs/plugins/transform-export-extensions
- 別名を付けて export し直すみたいな場合に import の構文と同じように出来る

```fuga.js
export var a = {
    hoge: 1
};
```

```hoge.js
// ES2015 だとこれができない
export * as b from './fuga.js';
```

```piyo.js
import {b} from './hoge.js';

b.a.hoge; //=> 1
```

### 追記１

- 前まで stage-2 だったけど
- https://github.com/leebyron/ecmascript-more-export-from

> This spec has been withdrawn in favor of the equivalent micro-proposals: export ns from and export default from. 

とのこと

### 追記２

- ES7 stage-1 に返り咲いたっぽい
- https://github.com/leebyron/ecmascript-more-export-from

# preset-stage-2

- http://babeljs.io/docs/plugins/preset-stage-2/

## syntax-dynamic-import

> This plugin only allows Babel to parse this syntax. If you want to transform it then see dynamic-import-webpack or dynamic-import-node.

とのこと

- [こういうやつ](https://webpack.github.io/docs/context.html#dynamic-requires)
    - やばそう

```js
require("./template/" + name + ".jade");
```

- 例 https://github.com/tc39/proposal-dynamic-import#example

## transform-class-properties

- http://babeljs.io/docs/plugins/transform-class-properties
- プロパティ宣言の空打ちが出来るようにしたいってことですかね

```js
class Base {
    hoge = 0;
}

class Hoge extends Base {
    hoge;
}

new Hoge(); //=> Hoge { hoge: 0 }
```

## transform-decorators

- http://babeljs.io/docs/plugins/transform-decorators
- https://github.com/babel/babel/commit/69fb1854d79e25f63e0b7553ba966716397eb382
 - 準備中っぽい？

### 追記

- disabled pending proposal update ってなってる

> Decorators are not currently supported
> Decorators are disabled in Babel v6, pending a proposal update – see babel/babel#2645.
> Until Babel officially supports decorators again, you might want to try the third-party transform-decorators-legacy plugin, or use Babel v5.

なるほど

# preset-stage-3

- http://babeljs.io/docs/plugins/preset-stage-3/

## transform-object-rest-spread

- http://babeljs.io/docs/plugins/transform-object-rest-spread
- Object にも Array みたいな rest 代入ができるように

```js
let [a, b, ...c] = [1, 2, 3, 4, 5];
a; //=> 1
b; //=> 2
c; //=> [ 3, 4, 5 ]

// みたいな感じで

let { x, y, ...z } = { x: 1, y: 2, z: 99, a: 3, b: 4};
x; //=> 1 
y; //=> 2
z; //=> { z: 99, a: 3, b: 4 }

// ってできる
```

## transform-async-generator-functions

- `async function* hoge() {}` みたいなやつへの対応
- `for - await - of` みたいなやつへの対応
 
```js
for await (const line of readLines(filePath)) {
  console.log(line);
}
```

- 例

```js
async function* genAnswers() {
  var stream = [ Promise.resolve(4), Promise.resolve(9), Promise.resolve(12) ];
  var total = 0;
  for await (let val of stream) { // val を待ってくれる？
    total += val;
    yield total;
  }
}

function forEach(ai, fn) {
  return ai.next().then((r) => {
    if (!r.done) {
      fn(r);
      return forEach(ai, fn);
    } else {
      return null;
    }
  });
}

var output = 0;
forEach(genAnswers(), val => output += val.value).
  then(() => console.log(output)); // 4+13+25 => 42
```

# stage 4 入りしてるっぽいやつら

> trailing-commas, async, exponentiation will be removed in the next major since they are stage 4 already

## syntax-trailing-function-commas

- 引数一覧のケツにカンマ付いてても怒らないでくれる優しさの提案

```js
function hoge(
    a,
    b,
    c, // ok
) { /* ... */ }
```

- http://babeljs.io/docs/plugins/syntax-trailing-function-commas

##  transform-async-to-generator

- http://babeljs.io/docs/plugins/transform-async-to-generator
- Promise を同期的に処理してくれるようにする機能

```js
function bar(msg) {
    return new Promise((res, rej) => {
        setTimeout(
            () => {
                console.log(msg);
                res();
            }, 10
        );
    });
}
```

```js
async function hoge() {
    await bar(1);
    await bar(2);
    await bar(3);
    console.log('finished');
}

hoge();
//=> 1
//=> 2
//=> 3
//=> finished 待ってから終わってくれる
```

```js
// async await 無い場合
function fuga() {
    bar(1);
    bar(2);
    bar(3);
    console.log('finished');    
}

fuga();
//=> finished 一足お先に終わっちゃう
//=> 1
//=> 2
//=> 3
```

##  transform-exponentiation-operator

- http://babeljs.io/docs/plugins/transform-exponentiation-operator
- 冪乗演算子
- 実際はもう Stage-4 に入ってる機能

```js
let n = 2**10; //=> 1024
n **= 2
n //=> 1048576
```