6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年3月18日 [ES2015] ECMAScriptモジュール (JavaScript Primer)

[ES2015] ECMAScriptモジュール

ECMAScriptモジュールはTodoアプリのユースケースで実際に動かしながら学ぶため、ここでは構文の説明とモジュールのイメージをつかむのが目的です。

モジュールは、保守性・名前空間・再利用性で使われます。

  • 保守性: 依存性の高いコードの集合を一箇所にまとめ、それ以外のモジュールへの依存性を減らせます
  • 名前空間: モジュールごとに分かれたスコープがあり、グローバルの名前空間を汚染しません
  • 再利用性: 便利な変数や関数を複数の場所にコピーアンドペーストせず、モジュールとして再利用できます

保守とは 対象の機器やシステム等が不便なく使えるように維持管理することです。

ECMAScriptモジュールの構文

ECMAScriptモジュールは、export文によって変数や関数などをエクスポートできます。 import文でエクスポートされたものをインポートすることが出来ます。

インポートとエクスポートの種類

  • 名前つき
  • デフォルト

名前つきエクスポート/インポート

名前つきエクスポート

const foo = "foo";
// 宣言済みのオブジェクトを名前つきエクスポートする
export { foo };
  • export文のあとに続けて{}を書き、その中にエクスポートする変数を入れることで、宣言済みの変数を名前つきエクスポートできます。
// 宣言と同時に名前つきエクスポートする
export function bar() { };
  • 関数のエクスポートはfuntionキーワードの前にexportをつけて行います。

名前つきインポート

export const foo = "foo";
export function bar() { }

変数fooと関数barを名前付きインポートしています。

import { foo, bar } from "./my-module.js";
console.log(foo); // => "foo"
console.log(bar); // => "bar"
  • import文のあとに続けて{}を書き、その中にインポートしたい名前つきエクスポートの名前を入れます。
  • 複数の値をインポートしたい場合は、それぞれの名前をカンマで区切ります。

名前つきエクスポート/インポートのエイリアス

internalFoo変数を名前つきエクスポートをas fooとすることでインポート時にfooとしても変数を認識することができます。

const internalFoo = "foo";
// internalFoo変数をfooとして名前つきエクスポートする
export { internalFoo as foo };

🔽インポート

// fooとして名前つきエクスポートされた変数をmyFooとしてインポートする
import { foo as myFoo } from "./named-export-alias.js";
console.log(myFoo); // => "foo"
  • export時もimport時も、asをつける事で別名を付けられます。

デフォルトエクスポート/インポート

デフォルトエクスポート

モジュールごとに1つしかエクスポートできない特殊なエクスポートです。

const foo = "foo";
// foo変数の値をデフォルトエクスポートする
export default foo;
  • 名前付きエクスポートでは変数を{}で囲っていましたがdefaultでは{}は必要ありません。
export default function() {}
  • 宣言と同時にデフォルトエクスポートすることが出来ます。
  • 関数やクラスの名前を省略することが出来ます。

変数宣言は宣言とデフォルトエクスポートを同時に行うことはできません。 変数宣言はカンマ区切りで複数の変数を定義できてしまうためです。

// 変数宣言と同時にデフォルトエクスポートはできない
export default const foo = "foo", bar = "bar";

デフォルトインポート

指定したモジュールのデフォルトエクスポートに名前をつけてインポートします。 次の例では my-module.jsのデフォルトエクスポートにmyModuleという名前をつけてインポートしています。 import文のあとに任意の名前をつけることで、デフォルトエクスポートをインポートできます。

my-module.jsファイルからexport

export default {
    baz: "baz"
};

default-import.jsにimport

// デフォルトエクスポートをmyModuleとしてインポートする
import myModule from "./my-module.js";
console.log(myModule); // => { baz: "baz" }
  • デフォルトインポートする際に名前を付けることが出来ます。
  • インポートの名前の指定時に{}を付けないのが特徴です。

名前つきインポートにおいてもdefaultという名前がデフォルトインポートに対応しています。 次のように、名前つきインポートでdefaultを指定するとデフォルトインポートできます。 ただし、defaultは予約語なので、この方法では必ずas構文を使ってエイリアスをつける必要があります。

// デフォルトエクスポートをmyModuleとしてインポートする
import { default as myModule } from "./my-module.js";
console.log(myModule); // => { baz: "baz" }
  • defaultという予約語を持っていると覚えておけば良いでしょう。

その他の構文

再エクスポート

別のモジュールからインポートしたものを、改めて自分自身からエクスポートし直すことです。 複数のモジュールからエクスポートされたものをまとめたモジュールを作るときなどに使われます。

// ./my-module.jsのすべての名前つきエクスポートを再エクスポートする
export * from "./my-module.js";
// [ES2020] ./my-module.jsのすべての名前つきエクスポートを名前空間オブジェクトとして再エクスポートする
export * as myNameSpace from "./my-module.js";
// ./my-module.jsの名前つきエクスポートを選んで再エクスポートする
export { foo, bar } from "./my-module.js";
// ./my-module.jsの名前つきエクスポートにエイリアスをつけて再エクスポートする
export { foo as myModuleFoo, bar as myModuleBar } from "./my-module.js";
// ./my-module.jsのデフォルトエクスポートをデフォルトエクスポートとして再エクスポートする
export { default } from "./my-module.js";
// ./my-module.jsのデフォルトエクスポートを名前つきエクスポートとして再エクスポートする
export { default as myModuleDefault } from "./my-module.js";
// ./my-module.jsの名前つきエクスポートをデフォルトエクスポートとして再エクスポートする
export { foo as default } from "./my-module.js";
  • export文のあとにfromを続けて、別のモジュール名を指定します。

すべてインポート

import * as構文は、すべての名前つきエクスポートをまとめてインポートします。 この方法では、モジュールごとの 名前空間 となるオブジェクトを宣言します。 エクスポートされた変数や関数などにアクセスするには、その名前空間オブジェクトのプロパティを使います。

エクスポートする側のファイル

export const foo = "foo";
export function bar() { }
export default {
    baz: "baz"
};

インポートする側のファイル

// すべての名前つきエクスポートをmyModuleオブジェクトとしてまとめてインポートする
import * as myModule from "./my-module.js";
// fooとして名前つきエクスポートされた値にアクセスする
console.log(myModule.foo); // => "foo"
// defaultとしてデフォルトエクスポートされた値にアクセスする
console.log(myModule.default); // => { baz: "baz" }

副作用のためのインポート

副作用 オブジェクトが変化することです。

side-effects.jsファイル

// グローバル変数を操作する(副作用)
window.foo = "foo";

インポートするファイル

// ./side-effects.jsのグローバルコードが実行される
import "./side-effects.js";

ECMAScriptモジュールを実行する

<!-- my-module.jsをECMAScriptモジュールとして読み込む -->
<script type="module" src="./my-module.js"></script>
<!-- インラインでも同じ -->
<script type="module">
import { foo } from "./my-module.js";
</script>
  • type="module"をつける事でECMAScriptモジュールになりエクスポート・インポートが可能になります。
  • type="module"属性が付与しない場合はECMAScriptモジュールの機能を持っていない通常のスクリプトとして扱われます。

参考

[ES2015] ECMAScriptモジュール