Marginalia

ECMAScriptのimport/exportについてのメモ

js-primer という JavaScript の本を書く上で ES2015 の import/export 構文の仕様について気になったところがあって調べたメモ

デフォルトエクスポートの扱い

まず、デフォルトエクスポートする方法がふたつある。ひとつは専用のexport default文によってエクスポートする方法。

export default function() {}

また、defaultという名前で名前付きエクスポートすれば、それもデフォルトエクスポートしたことになる。

function foo() {}export { foo as default };

デフォルトエクスポートがdefaultという固有名がつけられることは、Spec の https://www.ecma-international.org/ecma-262/6.0/#sec-exports-static-semantics-exportentries にかかれている。

{{< figure src=“https://cdn-ak.f.st-hatena.com/images/fotolife/l/lacolaco/20180626/20180626135151.png” caption=“default expor”>}}

デフォルトエクスポートをインポートする方法

デフォルトエクスポートされたものをインポートする方法もいくつかある。ひとつは一番シンプルなデフォルトインポート用の専用構文を使う。

import otherDefault from "other.js";

ところでこれは名前付きインポートで次のように書き換えられる。先程デフォルトエクスポートで書いたように、デフォルトエクスポートはdefaultという固有名でエクスポートされていることを利用できる。

import { default as otherDefault } from "other.js";

この構文、MDN の import 文のところには書かれていない。

{{< embed “https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import” >}}

ちなみに、default asというのは専用の構文ではなく、asによるエイリアス付きインポートの構文が適用されており、仕様上ではdefaultは特別なキーワードではなくただの IdentifierName として扱われているはず。 次のコードで default と foo は仕様上同じもので区別できない。

import { default as otherDefault, foo as otherFoo } from "other.js";

https://www.ecma-international.org/ecma-262/6.0/#sec-imports-static-semantics-boundnames

しかし、次のコードはシンタックスエラーになる。asによるエイリアスを使わない場合には、defaultfooは等価ではなくなる。 なぜならdefaultは ECMAScript の予約語であるからだ。

import { default, foo } from "other.js";

https://www.ecma-international.org/ecma-262/6.0/#sec-keywords

ここの肝は、Import 構文の ImportsList というもので、これは ImportSpecifier のリストだが、ImportSpecifier は ImportedBinding あるいはidentifierName as ImportedBinding と定義されている。

https://www.ecma-international.org/ecma-262/6.0/#sec-imports

つまり、import { default } と書いたときのdefaultImportedBindingとして扱われるが、これはシンボルとして参照可能なので予約語のチェックに違反する。

一方で、import { default as alias }と書いたときのdefaultidentifierNameであって、ImportedBindingではなくなり、予約語のチェックから外れる。

結果的に、default asはまるで普通のエイリアスされた名前付きインポートのように振る舞うことができる。 しかし仕様上はimport { default as ...}構文というのは存在していないが、デフォルトエクスポートや予約語の仕様が絡んだ結果、事実上の構文っぽいものになっているのがややこしい。

MDN の構文例は export と import どちらも、デフォルトエクスポートがdefaultという名前付きエクスポートとして振る舞っている例を扱っていないが、 これは仕様が複雑で説明が難しいからされてないんだろうか。

とりあえず自分の中で整理がついたので良し。