export / import と exports / require

## まとめ

- export / import は [ES2015 (ES6)](http://kangax.github.io/compat-table/es2016plus/) の構文。
  - export default とすると import 先の名前 (クラス名、関数名など) を省略できる。
- exports / require は [CommonJS](http://www.commonjs.org/) の構文で Node.js がサポートしている。

## export / import

default なしと default ありの 2 パターンあります。

### default なし (名前付きエクスポート)

export はクラス、関数、オブジェクトなどをエクスポートできますが、
今回はクラスを export してみます。
1 つのファイルに 2 つのクラスを用意してみました。

~~~export.js
export class Urashimasan {
  read() {
    console.log('Urashimasan says "亀の甲羅に腰かけるなどは、それは狂態と言つてよからう。"')
  }
}

export class KachiKachiYama {
  read() {
    console.log('A rabbit says "うるさいわね。泥の舟だもの、どうせ沈むわ。わからなかつたの？"')
  }
}
~~~

`import { クラス名 } from` でクラス名を指定します。

~~~import.js
import { Urashimasan, KachiKachiYama } from './export.js'

const u = new Urashimasan()
u.read()
const k = new KachiKachiYama()
k.read()
~~~

実行結果。

~~~sh
$ babel-node import.js
Urashimasan says "亀の甲羅に腰かけるなどは、それは狂態と言つてよからう。"
A rabbit says "うるさいわね。泥の舟だもの、どうせ沈むわ。わからなかつたの？"
~~~

ちなみに `import クラス名` で {} 無しだとエラーです。

~~~import.js
import Urashimasan from './export.js' // TypeError!!

const urashimasan = new Urashimasan()
urashimasan.read()
~~~

### default あり (デフォルトエクスポート)

export default の場合は 1 つのファイルに 1 つしか書けません。

~~~export-default.js
export default class Urashimasan {
  read() {
    console.log('Urashimasan says "亀の甲羅に腰かけるなどは、それは狂態と言つてよからう。"')
  }
}

// 2 つ export default しようとするとエラー!!
// Only one default export allowed per module.
//
// export default class KachiKachiYama {
//  read() {
//    console.log('A rabbit says "うるさいわね。泥の舟だもの、どうせ沈むわ。わからなかつたの？"')
//  }
// }
~~~

import 時に `{}` が不要です。

~~~import-default.js
import otogizoshi from './export-default.js'

const o = new otogizoshi ()
o.read()
~~~

省略せずにこう書くこともできます。

~~~import-default.js
import { default as otogizoshi } from './export-default.js'

const o = new otogizoshi ()
o.read()
~~~

実行結果。

~~~sh
$ babel-node import-default.js
Urashimasan says "亀の甲羅に腰かけるなどは、それは狂態と言つてよからう。"
~~~

## exports / require

Node.js では module.exports (または exports) に代入することでエクスポートします。

~~~ node-exports.js
class Urashimasan {
  read() {
    console.log('Urashimasan says "亀の甲羅に腰かけるなどは、それは狂態と言つてよからう。"')
  }
}

module.exports = Urashimasan;
~~~

require でインポートです。

~~~ node-imports.js
const urashimasan = require('./node-exports');

const u = new urashimasan();
u.read();
~~~

実行結果。

~~~sh
$ node node-import.js
Urashimasan says "亀の甲羅に腰かけるなどは、それは狂態と言つてよからう。"
~~~

## おまけ

### ECMAScript

ES2015 の ES は ECMAScript (エクマスクリプト) で Javascript の標準規格。
ES2015 は ES の 6 番目のバージョンなので ES6 とも呼ばれます。
ES2015 は let や const, class 構文, アロー関数など、たくさんの機能が追加されました。

前回の ES の 5 番目のバージョンは 2009 (ES5) なのでその 6 年後ですね。

### babel と babel-node

babel はJavascript のコンパイラー。
ES2015 の Javascript を、ES2015 に未対応の古いブラウザや環境でも実行できるようなコードを生成してくれます。
トランスパイラーとも呼ばれます。

Node.js はそのままでは export / import 文を実行できないため `babel-node` を使用して実行しました。

~~~sh
$ npm install --save-dev babel-cli babel-preset-env
$ exec $SHELL -l
~~~

プロジェクトの直下に .babelrc を作成すれば `babel-node`が使用できるようになります。

~~~.babelrc
{
  "presets": ["env"]
}
~~~

## 参考

- [MDN / export](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export)

>export 文は、モジュールから関数、オブジェクト、プリミティブな値をエクスポートするための JavaScript モジュールを作成するときに使用します。これらは別のプログラムで、 import 文で使用できます。

- [MDN / import](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import)

>import 文は、他のモジュールからエクスポートされたバインディング（関数、オブジェクト、プリミティブ）をインポートするために用います。


- [Node.js / module.exports](https://nodejs.org/docs/latest/api/modules.html#modules_module_exports)

>The module.exports object is created by the Module system. Sometimes this is not acceptable; many want their module to be an instance of some class. To do this, assign the desired export object to module.exports. Note that assigning the desired object to exports will simply rebind the local exports variable, which is probably not what is desired.

- [Node.js / require](https://nodejs.org/docs/latest/api/modules.html#modules_require_id)

>Used to import modules, JSON, and local files. Modules can be imported from node_modules. Local modules and JSON files can be imported using a relative path (e.g. ./, ./foo, ./bar/baz, ../foo) that will be resolved against the directory named by __dirname (if defined) or the current working directory.

## 実行環境

Mac

~~~sh
$ node -v
v10.15.3
~~~