JavaScriptのimportとexportを理解するには、前提知識としてモジュール、ES Modulus(ESM)、**CommonJS(CJS)**について知る必要があります。
モジュール
ソースコードを機能毎に分割して、メンテナンスしやすくする仕組みのことです。
モジュールには規格があり、代表的なものに**ES Modulus(ESM)とCommonJS(CJS)**が存在します。
ES Modules(ESM)
EcmaScriptの仕様に基づくモジュール管理システムのことです。
importとexportを使って読み込みや露出を行います。ESModulesは主にブラウザ側で使用します。
CommonJS(CJS)
Node.js上でモジュールを管理する仕組みのことです。
requireとexportsを使ってモジュールの読み込みや露出を行います。
Node.jsが開発された際にはJavaScriptをモジュール単位で開発する仕組みがなかったため、CommonJSが開発され、Node.jsでモジュール管理する仕組みが導入されました。
ES ModulesとCommonJSの違い
例えば、ESモジュールでimportしたものをCJSでrequireしてもエラーになります。モジュールシステムをまたいで使うことはできません。
ファイルの拡張子
基本的にどちらもJavaScriptのモジュール管理の仕組みなので、JSという拡張子で問題ありませんが、どちらの仕組みで動いているのか明示的にわかるようにするために分けることがあります。
基本的に、ブラウザ上だけで動かす際にはブラウザはESMのモジュール管理に基づいて動くため、JSという拡張子でいいですが、さまざまなプラットフォーム上で動かしたい場合は、Nodeモジュールのように異なるモジュール管理システムを導入していることがあるので、MJSとして、「これはESモジュールの仕組みで動いています」と明示的に表すこともあります。
前提知識がわかったところで、実際にimportとexportを使っていきます。
importとexport
前述のように、普段JavaScriptで使っているimportとexportはES Modulesの規格で書かれたものになります。
例として、moduleA.jsでexportして、moduleB.jsでimportする場合を考えてみます。
export let publicVal = 0;
export function publicFn() {
console.log('publicFn called');
}
import { publicVal, publicFn } from './moduleA.js';
console.log(publicVal); // 0
publicFn(); // publicFn called
moduleAでexportすることによって、moduleBからも同じ関数と変数を扱えるようになります。
また、以下のように「変数名 as 名前」と記載することによって、このファイル内でのみ使用できる任意の名前に変更することができます。
import { publicVal as val, publicFn as fn } from './moduleA.js';
console.log(val); // 0
fn(); // publicFn called
##asでimportする場合
*asでimportする場合、allModuleAというオブジェクトに対して、moduleAでexportしたものが格納されます。
export let publicVal = 0;
export function publicFn() {
console.log('publicFn called');
}
import * as allModuleA from './moduleA.js';
console.log(allModuleA); //
// publicVal: 0
// publicFn:(...)
console.log(allModuleA.publicVal) // 0
export default
export defaultの場合は変数の名前がありません。
例えば、export defaultに0と指定すると、exportされる値は「0」になります。
export default 0;
importする場合は、{}で括りません。
defaultでexportされたものは自由に名前をつけられます。
import defaultVal from './moduleA.js';
console.log(defaultVal); // 0
また、default export以外のものと一緒に使いたい場合は、{}の前に、カンマで区切って定義することができます。
import defaultVal, { publicVal, publicFn } from './moduleA.js';
CommonJSの規格の場合
commonJS規格のexportsを使った場合には、「exports.名前」となり、esModules規格のimportで読み込むことはできません。
exports.publicFn = function() {
console.log('publicFn called: ');
}
import publicFn from './moduleA.js'; // エラー
近年はJavaScriptを使ったプロジェクトの規模が大きくなっているので、モジュールを使って必要な機能だけimportとexportをすることでコードをメンテナンスしやすくすることが多いです。
参考資料