jsのモジュール化-commonjs,AMD,CMD,UMD,ES 6


前言
歴史上、jsはモジュール化の概念がなく、一つの大きな工事を多くの小さなモジュールに分解することはできない.これは多くの人が大規模で複雑なプロジェクトを開発するのに大きな障害を形成し、開発効率を明らかに低下させ、java、Pythonにはimportがあり、cssにも@importがあるが、jsにはこの方面のサポートがないことが理解できない.Es 6が出現してからこの問題を解決したが,これまで各コミュニティにも多くの解決策が現れ,比較的優れたAMD,CMD,commonjs,UMDが広く伝えられてきたが,今日ではこれらのモジュール化された解決策を分析する.
モジュールのロード
上記のいくつかのモジュール化スキームのモジュールロードにはどのような違いがありますか?まずes 6モジュールについて言えば、es 6モジュールの設計思想はできるだけ静的であり、コンパイル時に依存関係を確定することができ、コンパイル時ロードと呼ばれる.残りは実行時にのみ依存関係を決定します.これは実行時ロードと呼ばれます.次の例を見るとわかります.例えば、次のコードです.
let {a,b,c} = require("util");//   util      ,      3   
import {a,b,c} from 'util';// util   3   ,     

モジュール化されたいくつかのスキーム
AMD,CMD,commonjs,UMDのいくつかのモジュール化スキームを簡単に紹介します.
commonjs
commonjsはサービス側がモジュール化して採用した仕様であり,nodejsはこの仕様を採用した.commonjsの仕様に従って、個別のファイルはモジュールであり、ロードモジュールはrequireメソッドを使用し、このメソッドはファイルを読み取り、実行し、exportオブジェクトを返します.
// foobar.js
//    
var test = 123;
//    
function foobar () {
 
    this.foo = function () {
        // do someing ...
    }
    this.bar = function () {
        //do someing ...
    }
}
//exports             
var foobar = new foobar();
exports.foobar = foobar;
//  
var test = require('./foobar').foobar;
test.bar();

CommonJSロードモジュールは同期化されているので、ロードが完了してから後の操作を実行することができます.ノードみたいだjsは主にサーバのプログラミングに用いられ、ロードされたモジュールファイルは一般的にローカルハードディスクが存在するため、ロードが速く、非同期ロードの方式を考慮する必要がないため、CommonJS仕様が適用される.ただし、ブラウザ環境の場合は、サーバからモジュールをロードするには、非同期モードを使用する必要があります.AMD CMDソリューションがあります
AMD
AMDは「Asynchronous Module Definition」の略で、「非同期モジュール定義」AMDが簡潔な書き込みモジュールAPIを設計したことを意味します.
define(id?, dependencies?, factory);

最初のパラメータidは文字列タイプであり、モジュール識別を表し、オプションパラメータである.モジュールIDは、存在しない場合は、ローダで要求されたスクリプトのIDとしてデフォルトで定義されます.存在する場合、モジュールIDは最上位レベルまたは絶対的なIDでなければなりません.2番目のパラメータ、dependenciesは、現在のモジュール依存であり、モジュールによって定義されたモジュールによって識別される配列の字面量である.3番目のパラメータ、factoryは、インスタンス化が必要な関数またはオブジェクトです.
次の例を見ればわかる
define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
    export.verb = function(){
        return beta.verb();
        // or:
        return require("beta").verb();
    }
});

AMDといえばrequirejsを言わざるを得ません.RequireJSは最先端のモジュール化管理ツールライブラリであり、AMD仕様に従い、その著者はAMD仕様の創始者James Burkeである.AMDの基本的な考え方は、必要なモジュールをロードしてから、新しい関数を返します.すべての操作はこの関数の内部で操作され、前にロードされたモジュールはこの関数で呼び出すことができます.
CMD
CMDはseajsが普及の過程でモジュールの定義の規範化産出とAMDの早期実行とは異なり、CMDは遅延実行であるが、requirejsは2.0から遅延実行をサポートし始めた.これは書き方に依存する.AMDは依存前置を推奨し,CMDは依存が近いことを推奨する.AMDとCMDのコードを見て
//AMD
define(['./a','./b'], function (a, b) {
    //        
    a.test();
    b.test();
});
 
//CMD
define(function (requie, exports, module) {
    //        
    var a = require('./a');
    a.test();
    ...
    //   
    if (status) {
        var b = requie('./b');
        b.test();
    }
});

UMD
UMDはAMDとcommonjsを組み合わせたAMD適用ブラウザであり、commonjsはサービス側を適用し、両者を結合すればプラットフォーム間ソリューションに達する.UMDはまずAMD(defineが存在するかどうかを判断し、AMDモジュールでロードされたモジュールが存在するかどうかを判断し、nodejsをサポートしているモジュール(exportsが存在するかどうかを判断し、nodejsモジュールで使用されている方式が存在する.そうしないとwindowに掛けられ、グローバル変数で使用される.これも現在多くのプラグインヘッダの書き方であり、様々なモジュール化された書き方と互換性がある.
(function(window, factory) {
    //amd
    if (typeof define === 'function' && define.amd) {
        define(factory);
    } else if (typeof exports === 'object') { //umd
        module.exports = factory();
    } else {
        window.jeDate = factory();
    }
})(this, function() {  
...module..code...
})

ES6
Es 6のモジュールは自動的に厳格なモードを採用し、ヘッダに「use strict」モジュールがexportとimportの2つのコマンドで構成されているかどうかにかかわらず.
义齿
  • exportコマンドは、モジュールの最上位レベル(ブロックレベルの役割ドメイン内でない)にある限り、モジュールの任意の場所に表示できます.ブロックレベルの役割ドメイン内にある場合は、エラーが表示されます.
  • export文が出力する値は動的にバインドされ、そのモジュールをバインドします.

  • 义齿
    //a.js
    export default function(){
      console.log('aaa');
    }
    //b.js
    import aaa from 'a.js';

    1.export defaultを使用する場合、対応するimportはカッコを使用する必要はありません.importコマンドはdefaultに任意の名前を指定できます.2.export defaultが適用されない場合、対応するimportはカッコ3を使用する必要があります.1つのexport defaultは1回しか使用できません
    importコマンド
  • importコマンドは、モジュール全体のヘッダに昇格して最初に実行するので、ヘッダに直接書くことをお勧めします.これにより、表示と管理が容易になります.
  • import文は、以下の書き方
  • があるため、ロードされたモジュールを実行する.
      import 'lodash;

    上のコードはlodashモジュールのみが実行され、値は入力されていません.
    ソリッドロード
    全体的なロードには2つの方法があります
    //import
    import * as circle from './circle'
    //module
    //module       ,              
    module circle from './circle'

    ループロード
    サイクルロードについて話す前に、commonjsとes 6モジュールのロードの原理を理解します.
    commonjsモジュールロードの原理
    commonjsのモジュールはスクリプトファイルで、requireコマンドがスクリプトを最初にロードするとスクリプト全体が実行され、メモリにオブジェクトが生成されます.
    {
      id:"...",
      exports: {...},
      loaded: true,
      ...
    }

    上のオブジェクトではidはモジュール名、exportsはモジュール出力の各インタフェース、loadedはブール値であり、そのモジュールのスクリプトが実行済みかどうかを示す.その後、このモジュールを使用する場合はexportsに値を取り、requireコマンドを再実行してもモジュールは実行されず、キャッシュに値を取ります.
    Es 6モジュールにロードされた
    commonjsモジュールは出力値のコピーを入力します.つまり、値を出力すると、モジュール内部の変化はこの値es 6の動作メカニズムとcommonjsに影響しません.モジュールロードコマンドimportに遭遇してもモジュールは実行されず、動的な読み取り専用参照しか生成されません.本当に使用するときにモジュールに値を取りに行きます.es 6に入力されたモジュール変数は「シンボルリンク」にすぎないため、この変数は読み取り専用であり、彼に再割り当てを行うとエラーが報告される.
    import {obj} from 'a.js';
    obj.a = 'qqq';//ok
    obj = {}//typeError

    両者のロード原理を分析し、両者のサイクルロードを見てみましょう.
    commonjsのループロード
    commonjsモジュールの重要な特性は、ロード時に実行する、すなわちコードはrequireの時に実行され、commonjsのやり方は、ループロードが発生すると、実行済みの部分のみが出力、まだ実行されていない部分は出力されない.次にcommonjsでのループロードのコードを見てみましょう
    //a.js
    exports.done = false;
    var b = require('./b.js');
    console.log(' a.js ,b.done=',b.done);
    exports.done = true;
    console.log('a.js    ')
    //b.js
    exports.done = false;
    var a = require('./a.js');
    console.log(' b.js ,a.done=',a.done);
    exports.done = true;
    console.log('b.js    ')
    //main.js
    var a = require('./a.js');
    var b = require('./b.js');
    console.log(' main.js ,a.done=',a.done,',b.done=',b.done);

    上のコードでは、a.jsを実行するとき、a.jsはdone変数を出力し、別のスクリプトb.jsをロードします.このときaのコードはここに止まり、b.jsの実行が完了するまで待ってから、下に実行します.それからb.jsのコードを見て、b.jsも先にdone変数を出力して、それからa.jsをロードして、この時循環ロードが発生して、commonjsのメカニズムに従って、システムはa.jsの中のexportsの上で値を取りますが、実はa.jsは実行が終わっていないので、すでに実行した部分done=falseしか出力できなくて、それからb.jsは実行を続けて、実行が終わった後に実行権をa.jsに返して、そこでa.jsは実行が完了するまで実行を継続する.だからmainを実行する.js、結果はb.js、a.done=falsebである.js実行完了a.jsでb=done=truea.js実行完了main.jsでは,a.done=true,b.done=trueの上の例で2点を述べた.
  • b.jsにおいてa.jsは実行済みではなく、第1行
  • のみが実行された.
    2.main.jsで2行目まで実行すると、b.jsは再び実行されず、キャッシュされたb.jsの実行結果、すなわち4行目が出力される
    Es 6のループロード
    Es 6処理ループロードはcommonjsとは異なり、es 6はダイナミックリファレンスであり、モジュールロードコマンドimportに遭遇したときにモジュールを実行することはなく、モジュールへのリファレンスを生成するだけであり、開発者自身が出力の値を取ることができることを保証する必要がある.
    //a.js
    import {odd} from 'b.js';
    export counter = 0;
    export function even(n){
      counter++;
      return n==0 || odd(n-1);
    }
    //b.js
    import {even} from 'a.js';
    export function odd(n){
      return n!=0 && even(n-1);
    }
    //main.js
    import {event,counter } from './a.js';
    event(10)
    counter //6

    mainを実行します.js、commonjsの仕様に従って、上のコードは実行できません.aはbを先にロードし、bはaをロードしますが、aは出力値がありません.bのeven(n-1)はエラーを報告しますが、es 6は実行できます.結果は6です.