【JavaScript】ESModulesの使い方 import・export

##はじめに
VueCLIを勉強中しているのですが、モジュールの使い方について、しっかりとした理解が必要だと気づいたので、今回はESModeulsの使い方についてまとめておきます。


大前提としてモジュール管理とは何かという話ですが、
**「ソースコードを分割して、メンテナンスをし易くするための仕組み」**のことです。

１つのファイルに全ての処理を記述すると、当然ですがコードは肥大化してきますし、メンテナンスも大変です。

その為、**機能ごとに別ファイル（モジュール）に分割して必要に応じて読み込むことで、より効率なコード**になるわけです。

ESModulesとは、**ECMAScriptの規格に基づいたモジュール管理の仕組み**で、主にブラウザ上で動作します。**import**や**export**というキーワードを使って、モジュールの読み込みや出力を行います。

他にもNode.jsで動作する、Common.jsというモジュール管理の仕組みもあります。
こちらはrequireやexportsというキーワードを使い、モジュールの読み込みを行います。（しっかりと試せていませんが）


モジュール管理する方法は、実行環境などによって異なる種類があるということですね。

##ESModulesを試す
では、実際にESModulesのモジュール管理のやり方を試していきましょう。
まず、moduleAとmoduleBという名前のjsファイルと、ブラウザで結果を確認するのでhtmlを用意します。

```js:moduleB.js
let num = 10;

function methodA(){
    console.log("This number : " + num);
}

//num変数と、methodAメソッドをエクスポート。
export {num,methodA};
```


```js:moduleA.js

//インポート
import {num ,methodA} from "./moduleB.js";

console.log(num); // 10

methodA(); // This number : 10
```



```haml:index.html
<body>
    //typeをmoduleと指定する。
    <script type="module" src="moduleA.js"></script>
</body>
```

まず最初に、モジュール管理を行う場合、**スクリプト読み込み時に``type="module"``を指定する必要があります。**この指定が無いとESmodulesは使えません。

moduleBでは、オブジェクトリテラルにexportしたい変数や関数を指定します。

moduleAでは、importの後に、**moduleBでの指定と同じ様に``{num ,methodA}``**とします。ここで、**export時と異なる命名にすると、エラーになるので注意しましょう。**

そして、fromの後に、どのファイルからのimportをするかを指定します。ちなみに**ファイル指定では、../などパス指定をする必要があります。** ``from 'moduleB.js'``のように、ファイル名だけではエラーとなります。また、**拡張子の.jsも省略できないのでご注意を**。


こうすることで、moduleAでmoduleBの変数や関数を扱うことができるようになりました！

またexportとimportのモジュール名は同名にする必要があると言いましたが、**asを使うことで別名の変数や、関数に変更することも可能です。**

```js:moduleA.js
//asで名前変更
import {num as n ,methodA as A} from "./moduleB.js";

console.log(n); // 10

A(); // This number : 10
```

モジュール管理の基本的な流れは、こんな感じですが、

実はexportの方法は2種類あります。上のやり方は**名前付きexport**となります。

次は、もう１つの**export default**のやり方を見ていきましょう。

##export default

```js:moduleB.js
class Person{
    constructor(val){
        this.val = val;
    }

    print(){
        console.log(this.val * 2);
    }
}

//デフォルトエクスポート
export default Person;
```


```js:moduleA.js
import Person from "./moduleB.js";

const person = new Person(10);

console.log(person.val); //10

person.print(); // 20
```

今回はmoduleBでクラスを作り、それをmoduleAでimportします。

名前付きexportとの違いは、出力できるモジュールの数です。

**名前付きexportでは、先ほどの例の様に、変数や関数など複数のモジュールをエクスポートできますが、**

**export defaultの場合、エクスポートできるモジュールの数は1つとなります。**

なので例えば、下記の様に複数のクラスをexport defaultすることはできません。

```js:moduleB.js
class Person{
    constructor(val){
        this.val = val;
    }
    print(){
        console.log(this.val * 2);
    }
}

class Child{
    constructor(val){
        this.val = val;
    }
    print(){
        console.log(this.val * 2);
    }
}
//複数エクスポートはできない。エラー
export default {Person,Child}; //SyntaxError:
```

また、**defaultを使った場合、importのモジュール名はasを使うことなく変更することができます。**


```js:moduleA.js
//例えばモジュール名をPに変更
import P from "./moduleB.js";

//Pでインスタンス化
const person = new P(10);

console.log(person.val);

person.print();
```


ちなみに、**defaultは１つのスクリプトファイルに対して、１つという決まりがありますが、**

**名前付きexportは複数記述が可能です。**

なので、例えば以下の様に複数に分けてexportをすることもできます。

```js:moduleB.js
class Person{
    constructor(val){
        this.val = val;
    }
    print(){
        console.log(this.val * 2);
    }
}

let num = 300;

function methodA(){
    console.log("This number : " + num);
}

function methodB(){
    console.log("Hello World");
}

export default Person;
//exportを複数回使用
export  {num,methodA};
export  {methodB};
```

importでも、分割して読み込むことができます。
まとめて読み込みたい場合は、下の様にまとめて読み込むことも可能です。

```js:moduleA.js
//分けることもできる。必要に応じて読み込み。
import P from "./moduleB.js";
import {num} from "./moduleB.js";
import {methodA} from "./moduleB.js";
import {methodB} from "./moduleB.js";


//まとめてimportもできる。
import P,{num, methodA,methodB} from "./moduleB.js";
```

以上、ESmodulesでのモジュール管理についてでした。ありがとうございました。

##参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import