Babel.jsイントロダクション

f:id:axross:20150314170932p:plain

ここのところしばらく、プライベートでbabelを触っていて、次案件あたりから業務で使いたいなと思ったので、社内外への共有として書いておく。

Babelとは

Babelは、ECMAScript6(以下、ES6)のコードをECMAScript5(以下、ES5) のコードに変換するトランスパイラ(コードを変換してコードを生成するもの)。

ReactやFlowにフレンドリーであり、ReactのJSXをプラグインなしでES5のコードに変換できる。

また、Babel自体はNode.jsだけでなく、BrowserifyやWebpackを通してクライアントサイドで用いたり、KarmaやJestなどのテストランナーと共に用いることもできる。つまり、JavaScriptで書かれるコードの全てをES6で書くことができるということ。

導入

npm i babelして、npm bin環境下で使う。面倒臭かったらnpm i -g babelする。

Node.js

# ES6をES5のコードに変換して出力
$ babel script.es6 -o script.js

# sourcemapsの生成も可能
$ babel script.es6 -o script.js -s  # 外部sourcemaps
$ babel script.es6 -o script.js -t  # インラインsourcemaps

# ES6環境のままnode実行
$ babel-node app.es6

Node.jsではES6 → ES5な変換器的な使い方と、直接実行する使い方の両方ができる。後者のbabel-nodeは引数にファイル名を渡さなければREPLが起動する。けど、入力ごとにトランスパイラが動くようで、iffor() => {}などは1行で入力しないと構文エラーになる。

Browserify

ES6のimportなどの機能は、結局のところrequireに変換される。そのため、ブラウザでの利用にはBrowserifyやWebpackの併用が必要。

# transformにbabelifyを指定する
$ browserify app.es6 -o bundle.js -t

babelifyというtransformを使う。npm i babelify

var browserify = require('browserify');
var babelify   = require('babelify');

browserify({
  // ...
})
  .transform(babelify)
  // ...
  .bundle();

同様に、スクリプトとして利用する際もtransformにbabelifyを指定する。

mochaでのテスト

$ mocha --compilers es6:babel/register

babel/register--compilersに指定すればそのまま動く。

babel/registerはRequire hook用のモジュールで、mocha以外でも動く。あらゆるrequire()の前にrequire('babel/resgiter')しておけば、その後のrequire()はBabelのパーサーを通って解決される。

なぜ使うのか

ES6の機能は便利。なぜ使うのか、というか、ES6のこういう機能を使いたい、というベースで話をした方が自然な気がするので、そういう風に話をする。

Arrow function

var sum = (a, b) => {
  return a + b;
};

functionリテラルのショートカット。これだけならただ文字数少ないだけなのだが、Arrow functionにおいてはthisをレキシカルにするという効能がある。

var AnonymousUser = prop => {
  this.id   = prop.id;
  this.name = null;
};

AnonymousUser.prototype.revealName = callback => {
  $.ajax({ url: '/path/to/api' }).done(data => {
    this.name = data.name;
  });
};

このAnonymousUser#revealNameのAjaxコールバックの中でのthisは、レキシカルなものになっている。すなわち、Function#bind(this)するかのように、thisは定義時点でのスコープに束縛される。

実際には、selfのような一時変数にthisを逃がし、selfを通じてアクセスするように変換される。

特にReactではthisを多用するので、Function#bindselfの利用を減らせる/なくせるという点で嬉しい。

Template string

window.alert(`あなたは今「${location.href}」にいます。`);

文字列リテラル内に変数を埋め込み、実行時にその変数の中身を展開するというもの。+で強引に作ることが多かったので嬉しい。

Tagged templateという機能もあって、Template stringに埋め込まれた変数からゴニョゴニョして値を返すというものだけど、これはあまり使ってない。まだReactでしか触ってないからだと思う。

Class suger sintax

class User {
  constructor() {
    // var User = function() {} に相当する
  }
  
  instanceMethod() {
    // User.prototype.instanceMethod = function() {} に相当する
  }
  
  static memberMethod() {
    // User.memberMethod = function() {} に相当する
  }
}

ES6ではclass構文というものがある。これはコンストラクタ関数を作るシンタックスシュガーでしかないけど、書き方を統一でき、ある程度可読性を担保できるという意味でありがたい。

class Administrator extends User {
  // ...
}

また、class構文にはextendsキーワードも使うことができ、prototypeチェーンにおける継承関係も簡単に明示できる。

extendsしてる場合は、superが指定した親を表し、コンストラクタはsuper()、インスタンスメソッドはsuper.xxx()のようにアクセスできる。

Promise

bluebirdでなんとかしてたので、使うライブラリが1つ減るな、という所感。ただ、bluebirdはパフォーマンスキチガイが作ってるみたいな話を聞いたことがあるので、そのへんはもうちょっと調べて使いたい。

まとめ

他にもGeneratorとかREST parameterとか便利な機能はたくさんあるんだけど、意外とまだ必要に迫られていない。あまり凝ったことをしてないからだと思う。

というか、こんな記事読むくらいならdocs読んでもらった方がよっぽどいいなと思った。

ブレイクスルーJavaScript フロントエンドエンジニアとして越えるべき5つの壁―オブジェクト指向からシングルページアプリケーションまで

ブレイクスルーJavaScript フロントエンドエンジニアとして越えるべき5つの壁―オブジェクト指向からシングルページアプリケーションまで