技術メモなど

業務や日々のプログラミングのなかで気になったことをメモしています。PHP 成分多め。

JavaScriptのexport/importについて調べた

JavaScript再入門中。 今週はexport/importについてメモ。

export/importとは

export 文は、モジュールから関数、オブジェクト、プリミティブな値をエクスポートするための JavaScript モジュールを作成するときに使用します。これらは別のプログラムで、 import 文で使用できます。 エクスポートされたモジュールは宣言のあるなしにかかわらず strict mode で動作します。エクスポート文は、埋め込まれたスクリプトでは使えません。
export - MDN

import 文は、他のモジュールからエクスポートされたバインディング(関数、オブジェクト、プリミティブ)をインポートするために用います。インポートされたモジュールは宣言のあるなしにかかわらずStrict モードで動作します。import 文は、type="module" を指定しない限り、埋め込まれたスクリプトでは使えません。
import - MDN

exportキーワードは、ファイルの外部からアクセス可能であるべき変数や関数にラベル付けをする。
importキーワードは、exportされたものを読み込む。

エクスポートには、名前付きエクスポート(named exports)デフォルトエクスポート(default exports)の2種類がある。
名前付きエクスポートはモジュールごとに複数持つことができるが、デフォルトエクスポートは1つしか持てない。

// 関数helloをexport
export function hello(str) {
  console.log( `Hello, ${str}!` );
} // セミコロンはつけない(関数式にならないよう注意)

// 配列fooのexport
export let foo = ['bar', 'baz'];

// 定数Hogeのexport
export const Hoge = 'hoge';

// クラスUserのexport
export class User {
  constructor(name) {
    this.name = name;
  }
}

// デフォルトエクスポート
export default function(){
  console.log('default exports!');
}
// 関数helloをimport
import { hello } from "./sample.js";
hello('World'); //Hello World!

// 配列fooをimport
import { foo } from "./sample.js";
console.log(foo); //["bar", "baz"]

// 定数Hogeをimport
import { Hoge } from "./sample.js";
console.log(Hoge); //hoge

// クラスUserをimport
import { User } from "./sample.js";
console.log( (new User('tarou')).name ); //tarou

// デフォルトエクスポートを変数Sampleにインポート
import Sample  from "./sample.js";
Sample(); // default exports!

named exports

名前付きエクスポートをimportで読み込む際は変数名を波括弧で囲む必要があり、別名の設定や、複数同時指定などもできる。 また * as 変数名で一括インポートできる。

// 別名の設定
import { Hoge as Fuga }from "./sample.js";
console.log( Fuga ); //hoge

// 複数同時にimport
import {
    foo, 
    User as Tarou
} from "./sample.js";
console.log(foo); //['bar', 'baz']
console.log( (new Tarou('tarou').name) ); //tarou

// 一括import。すべての名前付きエクスポートをLibに読み込む
import * as Lib  from "./sample.js";
// プロパティ名でそれぞれのモジュールにアクセスできる
Lib.hello('World'); //Hello, World!
console.log( Lib.foo ); //['bar', 'baz']

default exports

デフォルトエクスポートは、defaultキーワードを付与するか、 変数名 as defaultで定義する。 また、変数名を必要とせず、無名関数等でもエクスポートできる。

// 無名関数でもエクスポート可(デフォルトエクスポートは1モジュールにつき1つであるため)
export default function (){ /*...*/ }

//同一モジュールに複数 default が定義されているとエラー
export default class{
    constructor() { ... }
}
//SyntaxError: Duplicate export of 'default'
// デフォルトエクスポート
let Hoge = "default exports";

// 以下は export default Hoge と等価
export { Hoge as default };

// 名前付きエクスポート
let Foo = "named exports";
export { Foo };

importで読み込む際に波括弧を指定しなかった場合、デフォルトエクスポートが読み込まれる。 また、defaultキーワードを使用することで別名をつけたり名前付きエクスポートと同時にimportしたりできる。

// 波括弧をつけないとデフォルトエクスポートがインポートされる
import Hoge from "./sample_2.js";
console.log( Hoge ); //default exports

// defaultキーワードの別名としてインポート
import { default as Fuga }from "./sample_2.js";
console.log( Fuga ); //default exports

// 名前付きと同時にimport
import {
    default as Piyo, 
    Foo
} from "./sample_2.js";
console.log(Piyo); //default exports
console.log( Foo );  //named exports

// 一括importした場合、defaultプロパティにデフォルトエクスポートが入っている
import * as Lib  from "./sample_2.js";
console.log( Lib.default); //default exports
console.log( Lib.Foo ); //named exports

import() 関数

importキーワードにはいくつかの制約がある。

  • ブロックの中に置くことはできない
  • モジュールパスを変数などで動的に生成することはできない
// ブロックのなかに置くことはできない
if(true){
    import { hello } from "./sample.js"; // Uncaught SyntaxError: Unexpected token {
}

// パスにプリミティブな文字列以外を使用することはできない。
let path = "./sample.js";
import { hello } from path; // Uncaught SyntaxError: Unexpected identifier

動的にimportする必要がある場合、import()関数を使用する。 import()関数はPromiseオブジェクトを返却するただの関数であるため、importキーワードのような制約を受けずに使用できる。

let path = "./sample.js";
import(path)
    .then((obj) => {
        // 各モジュールには、引数objのプロパティからアクセスできる。
        obj.hello('World');
        obj.default();
    });

本文中のコードは以下にまとめてあります。 export/import調査

参考文献