Pages

2012年8月31日金曜日

exports ってなに?

適当に使っていたけど、良く判らなかった exports 。ググって理解したことは、

  • moduleを輸出(export)する時に使う
  • requireを使って、moduleを呼び出すが、exportされたものしか利用できない
  • CommonJSの中の仕様で、当初のjavascriptにはない

と言うことで、早速 CommonJSを見る。

CommonJS Module 仕様 (英語)

相変わらず、英語に弱くて大変。むりやり、訳してみる。 (流石に、酷い訳なので、後で少しづつ手直しします。すみません。)

(ここから訳開始)

Moduleの状況 (使われ方、仕様)

  1. 一つのmoduleの中は、変数 requireがあり、それ(require)は、クラス(Function)だ。 (javascriptでは、クラスは関数の定義として提供される。この文章では、ある場合にはクラスと訳したほうが良いようだ。)
  2. "require"関数は、モジュールの識別子を(パラメータとして)受け取る。
  3. "require"は、外部のmoduleから輸出されたAPIを(戻り値として)返す。
  4. もし、依存の矛盾(cycle)が発生した場合、外部のmoduleは、その通過中の依存の一つから要求された瞬間に実行を完了することができない(APIを返せない)かもしれない。 この場合、"require"によって戻されたオブジェクトは、少なくとも、現在の(実行遅延中の)モジュールの実行前に外部モジュールによって輸出されたものを含んでいなければならない。
  5. もし、要求されたモジュールがなにも返すことができない場合、"require"は、エラーを投げなければならない。
  6. "require"クラスは、"main"プロパティを持つかもしれない。これ(main)は、読み込み専用で、削除されず、プログラムの最上位"module"であることを示します。もし、このプロパティが提供された場合、それ(main)は、メイン・プログラムの"module"オブジェクトに対し参照独立?でなければならない。

    1. "require" 関数は、"paths"属性を持つかもしれない。"Paths"は、path文字列の優先順位をしめす配列であり、(優先順位の)高いものから低いものへの順で、最上位モジュールの配置位置へのパスを格納している。
    2. "paths"プロパティは、sandboxの中に存在してはいけない。(sandboxは、セキュアなモジュール・システムである)
    3. "paths"属性は、全てのモジュールから、参照され独立していなければならない。referentially identical
    4. "paths"オブジェクトを他のオブジェクトで置き換えることは、無効だろう。
    5. "paths"属性が存在する場合、"paths"の内容の直接の修正は、(それが)対応するモジュールの検索の振る舞いにしたがって、反映されなければならない。
    6. "paths"属性が存在する場合、それは検索パスの消耗的なリストである。それは、ローダが内部的に、問われたパスの前後の他の配置を見るようなものだ。"paths"属性が存在する場合、それはローダの特権であり、パスを解決する、標準化する、正規化するために優先的に(使われる)。
  7. 一つのモジュールの中には、"exports"と呼ばれる変数がある。これは、オブジェクトであり、モジュールは、(モジュールが)実行できるように(自身の)APIを(そのオブジェクトに)加える。
  8. モジュールは、輸出(外部へのAPIの提供)の唯一の手段として、"exports"オブジェクトを利用しなければならない。
  9. モジュールには、変数 "moodule"が存在していなければならず、それはオブジェクトである。
  10. "module"オブジェクトは、読み取り専用であり、その"id"プロパティを削除しないこと。(idは)最上位のモジュールの"id"である。"id"プロパティは次の様なものでなければならない、つまり "require(module.id)"は、exports オブジェクトを返しますし、そのオブジェクトはmodule.idに由来するものです。(言い換えると、module.idは、別のモジュールに渡すことが出来、オリジナルのモジュールを返さなければならないことが要求される。)
  11. "module" オブジェクトは、URI文字列を持つかもしれないが、それはリソースを示す完全な形のURIであり、そのURIから、moduleは作られる。"uri"プロパティは、sandbox内に存在してはいけない。(参照できないので)

Module識別子について

  1. モジュール識別子は、/(スラッシュ)で構成された一連の単語である。
  2. 単語とは、CamelCaseスタイルの識別子と"."と".."でなければならない。
  3. モジュール識別子は、".js"のようなファイル識別子を持つかもしれない。
  4. モジュール識別子は、相対的か、トップレベルかも知れない。(ファイルパスのこと?)
  5. もし、最初の単語が、"."とか".."だったら、それは相対位置を示しています。
  6. 最上位のモジュール識別子は、概念的なモジュール・名前空間のルートの位置として解決される。
  7. 相対的なモジュール識別子は、"require"が書かれ、呼び出されたモジュールの識別子に対する相対的なものとして、解決される。

あいまいな点

この仕様は、以下の重要な事項で、相対的にあいまいな点を残している。

  1. モジュールは、データベース、ファイルシステム、ファクトリパターンのオブジェクト(Function)やライブラリにリンクし変換可能になっているかどうか
  2. PATHは、モジュール識別子を解決するためのモジュールローダにサポートされているか

サンプルコード

// math.js
exports.add = function() {
    var sum = 0, i = 0, args = arguments, l = args.length;
    while (i < l) {
        sum += args[i++];
    }
    return sum;
};
// increment.js
var add = require('math').add;
exports.increment = function(val) {
    return add(val, 1);
};
//program.js
var inc = require('increment').increment;
var a = 1;
inc(a); // 2

module.id == "program";

(ここで訳終了)

参考にしたサイト

以下のサイトは、大変参考になりました。ありがとうございます。

module.exports と exportsの違い

モジュールを輸出する - exports

まず、使われる側は、公開したい関数を exports というグローバル変数(?)のプロパティに代入します。 すると、他のプログラムは、エクスポートされた関数を使用できるようになります。逆に exports にセットしていない関数や変数は他から見えないので、グローバル名前空間が汚れるのを気にする必要がありません。素晴らしいですね。 (中略) モジュールを自身に含める - include モジュールを使う手段に include() 関数というのが用意されています。 require()と同じようにモジュールのファイル名(- .js)を渡して実行するのですが、exports変数にセットされた関数たちを、自分とこの名前空間に展開します。ローカル変数とか、名前がかぶっていたりすると、知らないうちに上書きされたりして危険な感じがします。

0 件のコメント:

コメントを投稿