ES6のモジュールシステム
1. 概要
あるファイルから別のファイルの関数や変数を参照したいときに、モジュールシステムを利用する。参照元では、importコマンドを使って外部のファイルを指定し、参照先では、exportコマンドを使って関数や変数を外部に公開する。
公開の方法として、大きく分けて、Named ExportsとDefault Exportsがある。両者はimport/exportコマンドの使い方が異なるので、章を分けて説明していく。
2. Named Exports
基本的には、以下のように、公開したいものの頭にexportを付ける。
// car.jsexportconstMAX_SPEED=200;exportfunctiongetSpeed(){retrunspeed;}exportfunctionsetSpeed(x){speed=x;}
あるいは、以下のように、ファイルの最後にまとめて書くこともできる。
// car.jsconstMAX_SPEED=200;functiongetSpeed(){retrunspeed;}functionsetSpeed(x){speed=x;}export{MAX_SPEED,getSpeed,setSpeed,};
外部に対して別名を見せたいときには、次のようにasを指定できる。
// car.jsconstMAX_SPEED=200;functiongetSpeed(){retrunspeed;}functionsetSpeed(x){speed=x;}export{MAX_SPEEDasCAR_MAX_SPEED,// 外部のファイルからはCAR_MAX_SPEEDという名前で見えるgetSpeed,setSpeed,};
上で作ったファイル「car.js」を参照するためには、importコマンドを用いる。
// main.jsimport{CAR_MAX_SPEED,getSpeed,setSpeed}from'car';setSpeed(100);
{ CAR_MAX_SPEED, getSpeed, setSpeed }
のところは、必ずしもすべてを指定する必要はなく、必要なものだけを指定してよい。
指定が面倒な場合には、次のように* as
を付けて、すべてを読み込むこともできる。
// main.jsimport*asCarfrom'car';Car.setSpeed(100);
3. Default Exports
上で説明したNamed Exportsでは、importの際に、読み込むものを列挙したり、* as
を指定する必要があった。これに対して Default Exportsでは、よりシンプルに、次のように書くことができる。
// main.jsimportCarfrom'car';Car.setSpeed(100);
これに対応するには、以下のように、export default
を指定する。
// car.jsconstMAX_SPEED=200;functiongetSpeed(){retrunspeed;}functionsetSpeed(x){speed=x;}// Objectにまとめて公開するexportdefault{MAX_SPEED:MAX_SPEED,getSpeed:getSpeed,setSpeed:setSpeed,};
この例ではObjectを公開しているが、変数でも関数でもクラスでも、何でもよい。ただし、export default
は、ファイルの中で1箇所しか書くことはできない。
なお、ES6ではオブジェクトのキーを省略表記できるようになったので、上の例は、次のように簡潔に書ける。
exportdefault{MAX_SPEED,getSpeed,setSpeed,};
こう書くと、先のNamed Exportsの例にそっくりになるが、構文的にはまったく別モノであるから注意が必要である。例えば、Named Exportsのようなas
を使うことはできず、次のコードはエラーとなる。
exportdefault{MAX_SPEEDasCAR_MAX_SPEED,// エラー!!getSpeed,setSpeed,};
4. いずれを使うべきか
「Exploring ES6」という書籍では、Named Exportsよりも、Default Exportsが推奨されている。これは、書式の簡潔さを根拠としている。
Exploring ES6より引用:
16.8.1 Default exports are favored
The module syntax suggesting that the default export "is" the module may
seem a bit strange, but it makes sense if you consider that one major design
goal was to make default exports as convenient as possible.
Quoting David Herman:
ECMAScript 6 favors the single/default export style, and gives the sweetest
syntax to importing the default. Importing named exports can and even should
be slightly less concise.
一方、下記の記事のように、export defaultを使うメリットがないと指摘する意見もある。これは主に、Tree-Shakingという最適化との相性が悪いことを根拠にしている。例えば、多数のメソッドを持つオブジェクトをexport defaultしていて、そのうちの一部のメソッドしか使わない場合、minifyしてもサイズが小さくならないらしい。
参考: Why we have banned default exports in Javascript and you should do the same
これら双方の主張を考えると、おおよそ、以下のように使い分けをすると良さそうである。
- ライブラリのように、使うかどうか分からないメソッドが多数ある場合には、Named Exports
- そうでなければ、Default Exports