【JavaScript：ES2015】モジュールについて（初学者向け）


# はじめに

この記事で記録している内容は、ES2015以降のJavaScritに組み込まれているモジュールに関する話です。

※内容に誤りがあった場合は申し訳ありません。ご指摘いただけると幸いです。

### そもそもモジュールってなんだ？
モジュールとは、[Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)において以下のように説明されています。
>システムを構成する要素となるもの。いくつかの部品的機能を集め、まとまりのある機能を持った部品のこと。


jsで書かれた処理を「モジュールにする」というのは言い換えると**機能ごとにファイルを分ける**ということになります。

すごく大雑把にいうと、
![スクリーンショット 2023-01-16 23.05.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/831462/8530293e-aa0a-671f-8bcc-7e16f6856262.png)

のような感じだと思います。


昔はJavaScriptにはファイルを分割してモジュールにする構文はありませんでしたが、ES2015にて導入されました。



# 実際にモジュール化してみる

### 手順1.環境を整える
ローカル環境でモジュールの勉強をする場合、エラーが発生します。[CORS（サーバー間リソース共有）](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)のエラーです。
サーバーを経由する必要があるので、VSCodeのServerLive機能やDockerなどでサーバーを準備してください（Dockerの環境構築が苦手なときはServerLive機能を調べてみてね）。

### 手順2.テスト用にhtmlファイルとjsファイルを準備する
分割前のファイル構成は以下だとします。
``` 
├─ index.html
└─ js
　└─ main.js
```
分割前の各ファイル内容は以下です。
```index.html
<html lang="jp">
    <meta charset="utf-8">
    <head>
        <script src="./js/main.js"></script>
    </head>
    <body>
　　　　<p>こんにちは</p>
    </body>
</html>
```
```main.js
//おなすさん農園の広さは1000平米
const area = 1000
//１平米あたりとれるおなすの本数は10本
const number = 10
//おなす1本あたりの単価
const unitPrice = 50

//収穫量を算出する関数
function getYeild(area, number) {
    return area * number
}

//売り上げを算出する関数
function getSalse(unitPrice, yeild) {
    return unitPrice * yeild
}

//getYeild関数で収穫量を算出し、それをもとに売り上げをコンソールに表示
const yeild = getYeild(area, number, term)
console.log(getSalse(unitPrice, yeild))
```
結果
![スクリーンショット 2023-01-15 18.43.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/831462/eafbd949-7633-0dbc-ffbb-ed1d3d19fd75.png)
※モジュールに関する記録に重点をおいており、あまり内容はありません。。。

### 手順3.モジュール化していく
（１）作成したモジュールのファイルを置くディレクトリを作成

``` 
├─ index.html
└─ js
　└─ main.js
　└─ module
```
※moduleディレクトリを作らないといけないわけではありません。モジュールとして作成したファイルをまとめておくために作成しています。

（２）モジュール化
収穫量を計算しているgetYeild関数を新しく『yeild.js』に、売り上げを計算しているgetSalse関数をsales.jsに分けて先ほど作成したmoduleディレクトリに追加したいと思います。

最終的なファイル構成
``` 
├─ index.html
└─ js
　└─ main.js
　└─ module
   └─ yeild.js
   └─ sales.js
```
分割後のファイル内容
```yeild.js
//おなすさん農園の広さは1000平米
const area = 1000
//１平米あたりとれるおなすの本数は10本
const number = 10

//収穫量を算出する関数
function getYeild(area, number) {
    return area * number
}
```
```sales.js
//おなす1本あたりの単価
const unitPrice = 50

//売り上げを算出する関数
function getSalse(unitPrice, yeild) {
    return unitPrice * yeild
}
```
```main.js
//getYeild関数で収穫量を算出し、それをもとに売り上げをコンソールに表示
const yeild = getYeild(area, number, term)
console.log(getSalse(unitPrice, yeild))
```
ひとまずファイルを分けました。しかしもちろん、このままではただファイルを分けただけで使い物になりません。（index.htmlではmain.jsしか読み込んでいないにも関わらず、main.jsにおいてファイル内に定義されていない関数が使用されています。また、関数に渡している引数も未定義です。）

yeild.js、salse.jsで定義した関数や変数をmain.jsで使用するために、加筆します。

```yeild.js
//おなすさん農園の広さは1000平米
export const area = 1000
//１平米あたりとれるおなすの本数は10本
export const number = 10

//収穫量を算出する関数
export function getYeild(area, number) {
    return area * number
}
```
```sales.js
//おなす1本あたりの単価
export const unitPrice = 50

//売り上げを算出する関数
exportfunction getSalse(unitPrice, yeild) {
    return unitPrice * yeild
}
```
```main.js
import {area,number,term,getYeild} from "./module/yeild.js"
import {unitPrice,getSalse} from "./module/salse.js"

//getYeild関数で収穫量を算出し、それをもとに売り上げをコンソールに表示
const yeild = getYeild(area, number, term)
console.log(getSalse(unitPrice, yeild))
```

**export**と**import**が出てきました。
他のファイルで使いたいプロパティや関数、クラスなどの前に**export**をつけ、他のファイルで**imort**する事で使用できます。

:::note warn
ネイティブなJavaScriptでは「import {area,number,term,getYeild} from "./module/yeild.js"」のように、importする際にファイルの拡張子までしっかり記述しなければいけません。「import {area,number,term,getYeild} from "./module/yeild"」とすることはできません。
:::


（３）scriptタグに[type="module"]を追加
最後に、index.htmlを以下のように修正します。
```index.html
<html lang="jp">
    <meta charset="utf-8">
    <head>
        <script src="./js/main.js" type="module"></script>
        <!-- 修正前 <script src="./js/main.js"></script>  -->
    </head>
    <body>
　　　　<p>こんにちは</p>
    </body>
</html>
```
これで、モジュールが適用されます。
モジュールが適用されていないとimportやexportは使う事ができません。

# いろんな記述の仕方
### 名前付きエクスポート
インポートするときに別名をつける
```.js
//export元の内容
export const amount = 10

//import先の内容
import {amount as onasuAmount} from "./module/test.js"
```
エクスポートするときに別名をつける
```.js
//export元の内容
const amount = 10
export {amount as onasuAmount}

//import先の内容
import {onasuAmount} from "./module/test.js"
```
### デフォルトエクスポート
```.js
//export元の内容
function onasu() {
   //処理
}
export default onasu

//import先の内容
import onasu from "./module/test.js"
```
デフォルトエクスポートの場合は、波かっこは不要です。
また、デフォルトエクスポートはひとつのファイルにつき一つまでしか指定できません。



出典：https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules