JavaScriptモジュール仕様(CommonJS、AMD)

6952 ワード

JavaScriptモジュールでは、コードを組織してモジュール化する方法を紹介しています.モジュール化はプライベートの属性と方法を隠し、公開インターフェースだけを暴く.そうすると他の人は初めから車輪を作る必要がなくて、直接にあなたのモジュールで定義された機能を使えばいいです.名前空間を確保しています.名前の衝突はありません.
しかし、基準がないと、誰もが自分の好みでモジュールを定義し、他人のモジュールを使うことに支障が出ます.本稿では、共通の定義JSモジュールの仕様を紹介します.
Common JS
NodejsのモジュールシステムはCommunJSモードを採用しています.CommunJS標準では、個々のファイルはモジュールであり、モジュール内で外部に露出する変数はexportオブジェクトに入れられ、任意のオブジェクト、関数、配列など、exportオブジェクトに入れられていないものはすべて私有と定められています.モジュールをrequire方法でロードすると、モジュールファイルを読み込んでexportオブジェクトを取得します.
例えば、hi.jsを定義します.
var str = 'Hi';

function sayHi(name) {
  console.log(str + ', ' + name + '!');
}

module.exports = sayHi;

hiモジュールではsayHi関数を定義し、exportsで暴露します.露出されていない変数strは外部からアクセスできません.他のモジュールがこの関数を使うなら、先にrequireというhiモジュールが必要です.
var Hi = require('./hi');
Hi('Jack');     // Hi, Jack!

第一行の変数Hiは、実はhi.jsでmodule.exports = sayHi;で出力されるsayHi関数です.
注意上にrequireでロードする時に書いたのは相対パスです.Nodejsに指定されたパスの下にモジュールをロードさせます.相対パスを省略するとデフォルトはnode_になります.modulesフォルダの下でhiモジュールを探していますが、見つけられなくてエラーが発生した可能性があります.もしあなたがロードしているのがNode内蔵モジュールか、npmダウンロードしてインストールしたモジュールであれば、相対パスは省略できます.
var net = require('net');
var http = require('http');

JavaScriptモジュールの文でJSモジュールの書き方を紹介しましたが、ここに出てくるmodule、export、requireはJSの新しい文法ですか?新しい文法ではなく、CommunJSの文法飴です.Nodeは上記のhi.jsをコンパイルします.
//   module  :
var module = {
    id: 'hi',
    exports: {}
};
var load = function (module) {
    function sayHi(name) {
        console.log('Hi, ' + name + '!');
    }

    module.exports = sayHi;
    return module.exports;
};
var exported = load(module);
//   module:
save(module, exported);

先にmoduleオブジェクトを定義します.属性IDはこのモジュール名であり、属性exportsは最終的に露出する必要があるオブジェクトです.したがって、私たちはhi.jsコードにmoduleオブジェクトを宣言したvarがないのに、module.export=sayHi;間違えないとは.なぜならmoduleはNodeがjsファイルをロードする前にすでに用意してくれています.最後にNodeはカスタム関数saveでこのmoduleオブジェクトを保存します.
Nodeはすべてのmoduleオブジェクトを保存した後、require()でmoduleを取得すると、Nodeはmodule.idによって対応するmoduleを見つけ、module.exportsに戻り、モジュールの出力を実現します.
CommunJSは同期しています.モジュール内の方法を呼び出したいという意味です.まずrequireでモジュールをロードしなければなりません.これはサーバー側のNodejsにとって問題ではありません.モジュールのJSファイルはローカルハードディスクにあります.CPUの読み込み時間は非常に速く、同期は問題ではありません.
しかし、クライアントブラウザ用のCommunJSローディングモジュールは、ネットワーク速度に依存します.同期を採用すると、ネットワークの情緒が不安定な場合、ページが詰まります.したがって、クライアントに対してAMD非同期モジュール定義が生じる.
AMD
AMD(Aynchronous Module Definition)非同期ローディングモジュールです.AMD標準規定は、モジュールをdefineで定義し、requireでモジュールをロードする.
define(id, [depends], factory);  
require([module], callback);

define定義モジュールの例を先に見ます.
define(['module1', 'module2'], function (module1, module2) {
    ……
    return { … };
});

最初のパラメータIDはあなたのモジュール名です.上記の例は省略します.実はこのIDはあまり役に立たないです.開発者に見せたのです.
第二のパラメータ[depends]は、モジュールに依存する他のモジュールであり、上記の例では、モジュールは他の2つのモジュールmodule 1およびmodule 2に依存する.定義されたモジュールが他のモジュールに依存しない場合は、パラメータは省略できます.
三つ目のパラメータfactoryは、一つのオブジェクトを外部に使用するために生産しています.(ある資料でこのパラメータをcalbackと命名しています.calbackの意味は曖昧で、factoryと名づけた方がいいと思います.)
モジュールを定義してから、レギュイルでモジュールをロードする例を見ます.
require(['yourModule1', 'yourModule2'], function (yourModule1, yourModule2) {
    ……
}); 

Common JSのrequire方法と比較してもいいです.AMDのrequireは一つのパラメータのcalbackを多くしました.
最初のパラメータは、ロードが必要なモジュール名で、複数のモジュールをロードするという意味です.モジュールをロードする時、このモジュールのdefineに[depends]パラメータがあれば、先に[depends]で指定された依存モジュールをロードします.[depends]内の依存モジュールをロードした後、define内のfactory方法を実行してこのモジュールの実例を得ます.次に、この例をパラメータとして第2のパラメータcalbackに順次入力する.
二つ目のパラメータcalbackコールバック関数は、最初のパラメータに基づいてモジュールを順次ロードした後に得られる例示的なオブジェクトです.などの最初のパラメータで指定したモジュールを全部ロードしたら、このカルバックを実行します.
requireロードプロセスはいくつかのステップに分けられますか?
第1ステップは、依存リストのモジュール名をURLに変換し、よくあるのはbasePath+moduleID+「.js」である.たとえば:
require(["aaa", "bbb"], function(a, b){});
//  require      :
//require(["http://1.2.3.4/aaa.js", 
//       "http://1.2.3.4/bbb.js"], function(a, b){});

第二のステップは、モジュールがロードされているかどうか(状態が2かどうか)、またはロードされているかどうかを検出対象配列から確認する(状態が1かどうか).このノードをロードしたことがない限り、ロードフローに入ります.
ステップ3は、このモジュールの状態を1に設定し、ロードされていることを示します.scriptタグを作成し、モジュールのURLをsrcに追加し、onload、onreadystatechange、onerrorイベントを結びつけて、scriptをDOMツリーに挿入してロードを開始します.ブラウザのロードが完了するとバインディングのオンイベントが発生します.モジュールの状態を2に変更して、ロードが完了したことを示します.
第四のステップは、モジュールのURL、依存リスト、状態などを第二のステップ検出用の検出対象配列に構築する.
モジュールに必要な変数と方法のコードを全部calbackに入れてもいいです.requireの下のコードは継続して実行します.このようにブラウザが仮死に引っかかることを避けることができます.
AMD仕様を実現したJSライブラリには、require.jsがあります.require.jsを使った例を見てください.
//myModule1.js
define(function() {
    var m1 = {};
    m1.say = function() {
        console.log('Hi myModule1!');
    }
    return m1;
});

//myModule2.js
define(['myModule3'], function(m3) {
    var m2 = {};
    m2.say = function() {
        m3.say();
        console.log('Hi myModule2!');
    }
    return m2;
});

//myModule3.js
define(function() {
    var m3 = {};
    m3.say = function() {
        console.log('Hi myModule3!');
    }
    return m3;
});

//HTML
console.log("before require");
require(['myModule1','myModule2'], function(m1, m2){         
    m1.say();
    m2.say();
});
console.log("after require");
//before require
//after require
//Hi myModule1!
//Hi myModule3!
//Hi myModule2!

HTMLではまずconsole.log(“before require”);を実行して、第一条を印刷します.
次にrequireを実行します.require.jsはAMD非同期ローディングであるため、requireを実行したconsole.log(“after require”);文は第二条を印刷します.
requireを実行してモジュールを順次ロードします.先にmyModule 1をロードします.myModule 1のdefineには[depends]パラメータがなく、他のモジュールに依存しないことが分かりました.したがって、define内のfactory方法を実行してmyModule 1のインスタンスオブジェクトm 1を獲得します.
myModule 2を再読み込みします.myModule 2がmyModule 3に依存していることが分かりましたので、myModule 3をロードします.myModule 3には[depends]パラメータがなく、他のモジュールに依存しません.このためfactoryを実行してmyModule 3の対象例m 3を獲得しました.
myModule 3をロードした後、myModule 2を実行するfactoryはmyModule 2のインスタンスオブジェクトm 2を獲得します.
myModule 2もロードが完了したら、requireのモジュールは全部ロード済みで、コールバック関数を実行します.前に得られた例のオブジェクトm 1とm 2はパラメータとしてコールバック関数に伝えられます.
実行m1.say();は第3条を印刷します.m2.say();を実行して、方法によって定義して、先にm3.say();を実行して第4条を印刷して、更にconsole.log(‘Hi myModule2!’);を実行して第5条を印刷します.
AMDに厳密に準拠していないライブラリがありますが、define関数で定義されているモジュールは、シム技術(いわゆるシムはスペーサーです.つまり、新しいAPIを古い環境に導入し、古い環境に既存の手段で実現します.)を使用する必要があります.例えばrequire.jsはrequire.co.figのためにshim属性を定義しています.AMD規格を採用していないundersscoreとbackboneの2つのライブラリをそれでロードします.
require.config({
    shim: {
        'underscore':{
            exports: '_'
        },
        'backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        }
    }
});

もちろん本編ではrequire.jsを紹介していません.もっとrequire.jsの使い方は自分で公式サイトを参照してください.
締め括りをつける
Nodejsに採用されたサーバー側のCommonJS仕様であれ、クライアントのAMD仕様であれ、私達がカスタマイズしたモジュールを標準化して、他の人に使用しやすいです.
作者:張歆琳_琳リンク:https://www.jianshu.com/p/fc858878d891 出所:著作権は著者の所有になります.商業転載は作者に連絡して授権を獲得してください.商業転載ではないので、出典を明記してください.