JavaScript

ES6のexportについて

ES6のexportについて

webpackのチュートリアルとかがES6なので、読めないとやばい、開発のときは書けないとやばいということで調べてみました。

exportについて

モジュール化を行うexportには、モジュールごとに複数のexportを行うnamed exportsとモジュールごとに1つのexportを行うdefault exportsがある。

named exports

モジュールは前言の先頭にexportとつけることで、複数のモジュールをexportすることができる。

lib.js
export const sqrt = Math.sqrt;
export function square(x) {
  retrun x * x;
}
export function diag(x, y) {
  return sqrt(square(x) + square(y));
}
main.js
import { square, diag } from 'lib'; //libからsquareとdiagというモジュールをインポートする
console.log(square(11));
console.log(diag(4, 3));

モジュール全体をインポートして、named exportsをプロパティ表記法で参照することもできる。

import * as lib from 'lib'; // lib.jsの全てのモジュールをlibというオブジェクトに格納するみたいなイメージ
console.log(lib.square(11));
console.log(lib.diag(4, 3));

CommonJSと同じ記述で、Node.jsのモジュールのエクスポートと重複しないようにも書ける。

lib.js
var sqrt = Math.sqrt;
function square(x) {
  return x * x;
}
function diag(x, y) {
  return sqrt(square(x) + square(y));
}
module.exports = {
  sqrt: sqrt,
  square: square,
  diag: diag,
};
main.js
var square = require('lib').square;
var diag = require('lib').diag;
console.log(square(11));
console.log(diag(4, 4);

Default exports

フロントの開発でも、1つのモデルに付き1つのモジュールでコンストラクタやクラスが使われる。
ES6のモジュールは、最も重要なexportする値default exportという形で選択できる。

myFunc.js
export default function() {...};
main1.js
import myFunc from 'myFunc';
myFunc();

default exportsを使ったクラスのモジュールはこんな感じ。

myClass.js
export default class {...};
main2.js
import MyClass from 'MyClass';
let inst = new MyClass();

default exportの式の宣言は名前を持たない。
代わりに、モジュールの名前で識別する。

名前付きのDefault exports

ライブラリは単一の関数だが、追加のサービスはその関数のプロパティを通して提供される。
// ドキュメントを読んでもピンとこなかったのであとで調べます。

ドキュメントでは、CommonJSでのjQueryとUnderscope.jsの例があった。

underscore.js
var _ = function(obj) {
  ...
};
var each = _.each = _.forEach = function(obj, iterator, context) {
  ...
};
module.export = _;
main.js
var _ = require('underscope');
var each = _.each;

今や上記のCommonJSはES6モジュールとして書き直されている。
CommonJSよりもES6の方がフラットフラット

underscore.js
export default function(obj) {
  ...
};
export function each(obj, iterator, context) {
  ...
}
export { each as forEach };
main.js
import _, { each } from 'underscore';

default exportはnamed exportでもある

default exportは、実はdefaultという名前のエクスポート。
以下は同じ意味になる。

import { default as foo } from 'lib';
import foo from 'lib';

同じように以下の2つのモジュールも同義。

module1.js
export default 123;
module2.js
const D = 123;
export { D as default };

ES6のモジュールのデザインのゴール

  1. default exports推奨
  2. 静的なモジュール構成
  3. 同期と非同期両方のローディングをサポート
  4. モジュール間の巡回依存のサポート

英語力がなかったのと、イメージがつかめなかったのとであまり理解できず。。。。
あとで読み直す( http://2ality.com/2014/09/es6-modules-final.html )

import方法

ES6ではモジュールのimport方法はいくつかある。

// Default exports and named exports
import theDefault, { named1, named2 } from 'src/mylib';
import theDefault from 'src/mylib';
import { named1, named2 } from 'src/mylib';

// Renaming import named1 as myNamed1
import { named1 as myNamed1, named2 } from 'src/mylib';

// Importing the module as an object
//(with one property per named export)
import * as mylib from 'src/mylib';

// Only load the module, don't import anything
import 'src/mylib';

export方法

モジュールの中にあるものをエクスポートする方法は2つある。
exportで宣言を行う。

export var myVar1 = ...;
export let myVar2 = ...;
export const MY_CONST = ...;

export function myFunc() {
  ...
}
export function* myGeneratorFunc() {
  ...
}
export class MyClass {
  ...
}

default exportは関数やクラスを含む式。

export default 123;
export default function (x) {
  return x;
};
export default x => x;
export default class {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
};

モジュールの最後にエキスポートしたい全てを羅列できる。

const MY_CONST = ...;
function myFunc() {
  ...
}

export { MY_CONST, myFunc };

別の名前でもエキスポートできる。

const MY_NAME = ...;
function myFunc() {
  ...
}

export { MY_CONST as THE_CONST, myFunc as theFunc };

Re-exporting

Re-exportingとは、別のモジュールのエクスポートを現在のモジュールのエクスポートに追加すること。
他のモジュールの全てのエクスポートを追加することもできる。

export * from 'src/other_module';

より選択的なRe-exporting

export { foo, bar } from 'src/other_module';

// Export other_modules’s foo as myFoo
export { foo as myFoo, bar } from 'src/other_module';

ES6のモジュールローダー API

モジュールを扱う宣言の文法に加えて、APIもある。
APIでは以下のことができるようになる。

  • プログラムに依るモジュールとスクリプトの操作
  • モジュールの読み込みの設定
  • ローダーは、import … fromのモジュールの指示詞に従ってモジュールの読み込みなどの処理を行う。 コンストラクタはReflect.Loader。 各プラットフォームは、モジュールロードの得知恵のスタイルを実装するグローバル変数System(システムローダー)にカスタマイズされたインスタンスを保持する。

モジュールのインポート

プログラムでのモジュールのインポート。

System.import('some_module')
.then(some_module => {
  // Use some_module
})
.catch(error => {
  ...
});

System.import()は以下を可能にする。

  • scriptタグの中でモジュールが使えるようになる
  • 条件に合わせてモジュールを読み込める

System.importでは、単一のモジュールを取得する。
Promise.allを使用すると複数のモジュールをインポートできる。

Promese.all(
  ['module1', 'module2', 'module3']
  .map(x => System.import(x)))
.then(([module1, module2, module3]) => {
  // User module1, 2, 3
});