先端モジュール化、Common JS、AMD、CMD及びES 6モジュール化


前言
前までは先端のモジュール化について徹底的に理解していませんでしたが、普段使っているのはES 6モジュール化だけです.他のいくつかのモジュール化の規範用も少なく、理解が足りないです.
一、モジュール化に対する理解
  • モジュール化とは?モジュール開発は一種の管理方式であり、問題を解決する方案であり、一つのモジュールは特定の機能を実現するファイルであり、モジュールがあれば、他の人のコードをより便利に使うことができます.どんな機能がほしいなら、どのモジュールをロードしますか?後になって、みんながよく知っているAMD規格、CMD規格、及びES 6が持っているモジュール化規格があります.
  • モジュール化によるメリット
  • 名前の衝突を解決します.
  • は、多重化
  • を提供する.
  • コードの維持性を高める
  • フレキシブルアーキテクチャ、焦点分離、モジュール間の組み合わせ、分解を容易にする
  • 人あまりの協力は互いに干渉しない.
  • モジュール化規範の発展プロセス
  • オリジナルの書き方(大域function)モジュールは、モジュールとしても、異なる関数(および記録状態の変数)を簡単に一緒に置くだけで、特定の機能を実現する方法のセットである.
  • function m1 () {
         
    	// ...
    }
    
    function m2 () {
         
    	// ...
    }
    
    このように上の関数m 1()とm 2()を書いてモジュールを作って、使う時に直接呼び出してもいいです.しかし、問題は非常に明確です.グローバル変数が汚染されています.他のモジュールと変数名の衝突が発生しないことは保証できません.また、モジュールメンバー間に直接関係が見られません.
  • namespace書き方(簡単な対象)上記の書き方による欠点を解決するために、モジュールは対象として作成し、すべてのモジュールのメンバーはこの対象に入れます.これによりグローバル変数が減少し、ネーミング衝突が減少します.
    const myModule = new Object({
         
    	count: 0,
    	m1: function () {
         
    		console.log('m1:' + this.count);
    		
    	},
    	m2: function () {
         
    		console.log('m2:' + this.count)
    		
    	}
    })
    
    //   
    myModule.m1() // m1:0
    
    //         
    myModule.count = 5;
    myModule.m1() // m1:5
    
    上の関数m 1とm 2は、すべてmyModuleオブジェクトにパッケージされています.使用時は、このオブジェクトの属性を呼び出します.ただし、このような書き方は全モジュールのメンバーを暴露し、内部の状態は外部に書き換えられます.例えば、外部コードは、内部カウンタの値を直接変更することができる.
  • は、直ちに関数書き方(匿名関数自己実行、クローズド)を実行する
  • .
    const myModule = (function () {
         
    	let count = 0;
    	let m1 = function () {
         
    		console.log('m1:' + count)
    	};
    	let m2 = function () {
         
    		console.log('m2:' + count)
    	}
    	return {
          m1, m2 };
    })()
    
    //                count   
    console.log(myModule.count); // undefined
    
  • は、直ちに関数拡張(導入依存)を実行する
  • .
    const myModule = (function ($) {
         
    	//         JQuery
    })(JQuery)
    
    //              ,                
    
    二、モジュール化の規範
    1.CommunJS
    (1)概要Nodeアプリケーションはモジュールで構成され、CommunJSモジュール仕様を採用する.各ファイルはモジュールです.自分の役割領域があります.一つのファイルで定義されている変数、関数、クラスはすべてプライベートです.他のファイルには見えません.サーバー側では、モジュールのロードは実行時に同期してロードされます.ブラウザ側では、モジュールを事前にコンパイルして包装処理を行う必要があります.
    (2)特徴
  • すべてのコードはモジュールのスコープで動作し、グローバルスコープを汚染しません.
  • モジュールは複数回のロードができますが、最初のロード時に一回だけ実行され、その結果がキャッシュされます.後で再読み込みして、直接キャッシュ結果を読み取ります.モジュールを再起動するには、キャッシュをクリアする必要があります.
  • モジュールによってロードされる順序は、コードに現れる順序に従う.
  • (3)基本文法暴露モジュール:module.exports=valueまたはexports.xxx=value導入モジュール:require(xxx)、第三者モジュールであれば、xxxはモジュール名とする.カスタムモジュールの場合、xxxはモジュールファイルのパスです.
    Common JSが露出しているモジュールは一体何ですか?CommonJS仕様規定により、各モジュールの内部で、module変数は現在のモジュールを表します.この変数はオブジェクトで、そのexport属性(すなわちmodule.exports)は対外的なインターフェースです.モジュールをロードすると、モジュールのmodule.exports属性がロードされます.
    // example.js
    let count = 5;
    let incrementCount = function () {
         
    	return ++count
    }
    module.exports.count = count;
    module.exports.incrementCount = incrementCount;
    
    // require.js
    const example = require('./example.js');
    console.log(example.count); // 5
    console.log(example.incrementCount()); // 6
    
    requireコマンドは、モジュールファイルをロードするために使用します.requireコマンドの基本機能は、JavaScriptファイルを読み込んで実行し、モジュールのexportオブジェクトに戻ります.指定モジュールが見つからなかったら、エラーが発生します.
    (4)モジュールのローディング機構CommunJSモジュールのローディング機構は、入力された値のコピーです.つまり、一度値を出力すると、モジュール内部の変化はこの値に影響しません.この点はES 6モジュール化と大きな違いがあります(ES 6入力は値の参照です).
    // example.js
    let count = 5;
    let incrementCount = function () {
         
    	return ++count
    }
    
    module.exports = {
          count, incrementCount };
    
    // require.js
    const example = require('./example.js');
    
    console.log(example.count); // 5
    example.incrementCount();
    console.log(example.count); // 5
    
    2.AMD
    (1)概要
    CommunJS標準ロードモジュールは同期されています.つまり、ロードが完了してこそ、後の操作が実行されます.AMDは「Aynchronous Module Definition」の略語で、「非同期モジュール定義」という意味です.モジュールを非同期的にロードします.このモジュールに依存するすべてのステートメントは、ロードが完了するまで一つのコールバック関数で定義されます.Node.jsは主にサーバープログラミングに使われていますので、モジュールファイルは一般的にはすでにローカルハードディスクに存在していますので、ロードが速く、非同期ロードの方式を考慮しなくてもいいです.ただし、ブラウザ環境であれば、サーバー側からモジュールをロードする場合は非同期モードが必要となりますので、ブラウザ側はAMD仕様が一般的です.また、AMD仕様はCommonJS仕様よりもブラウザ側での実装が早いです.
    (2)基本文法
    /**
    * @param id
    * @param dependencies
    * @param factory
    */
    
    define(id?: String, dependencies?: String[], factory: Function|Object);
    
    idはモジュールの名前であり、オプションのパラメータである.dependenciesは、依存するモジュールリストを指定しています.これは配列であり、オプションのパラメータでもあります.各依存モジュールの出力はパラメータとして一度にfactoryに入力されます.dependenciesが指定されていない場合、そのデフォルト値は「require」、「exports」、「module」です.factoryは最後のパラメータであり、これはモジュールの具体的な実装を包み、関数またはオブジェクトである.関数の場合、その戻り値はモジュールの出力インターフェースまたは値です.
    (3)用例
    myModuleというモジュールを定義して、jQueryモジュールに依存します.
    define('myModule', ['jquery'], function($) {
         
        // $   jquery      
        $('body').text('hello world');
    });
    
    //   
    require(['myModule'], function(myModule) {
         });
    
    複数のモジュールの定義に依存します.
    define(['jquery', './math.js'], function($, math) {
         
        // $   math      factory
        $('body').text('hello world');
    });
    
    モジュール出力:
    define(['jquery'], function($) {
         
    
        var HelloWorldize = function(selector){
         
            $(selector).text('hello world');
        };
    
        // HelloWorldize            
        return HelloWorldize;
    });
    
    モジュール定義の内部参照の依存性:
    define(function(require) {
         
        var $ = require('jquery');
        $('body').text('hello world');
    });
    
    3.CMD
    (1)概要
    CMD仕様はブラウザの端に専用です.モジュールのロードは非同期です.モジュールが使用する時にロードして実行します.CMD仕様はCommon JSとAMD仕様の特徴を統合しています.Sea.jsでは、JavaScriptモジュールはすべてCMDモジュール定義仕様に従う.
    (2)基本文法
    /**
    * @param {String} id
    * @param {Array} dependencies
    * @param {Function | Object | String} factory
    */
    define(id?, dependencies?, factory)
    
    ファクトリーが対象、文字列の場合、モジュールを表すインターフェースがそのオブジェクト、文字列です.
    define({
          "foo": "bar" });
    
    define('I am a template. My name is {
         {name}}.');
    
    factoryを関数とすると、モジュールの構造方法を表します.この構成方法を実行すると、モジュールが外部に提供するインターフェースが得られます.factoryメソッドは実行時、デフォルトでは三つのパラメータが入ってきます.require、exports、module:
    define(function(require, exports, module) {
         
    
      //     
    
    });
    
    (3)簡単な用例
    依存しないモジュールを定義:
    define(function(require, exports, module){
         
      	exports.xxx = value
      	module.exports = value
    })
    
    依存モジュールを定義:
    define(function(require, exports, module){
         
      //      (  )
      var module2 = require('./module2')
      //      (  )
        require.async('./module3', function (m3) {
         
        })
      //    
      exports.xxx = value
    })
    
    4.ES 6モジュール化
    (1)簡単なES 6モジュールの設計思想はできるだけ静的化されており、コンパイル時にモジュールの依存関係や入出力の変数が確定できるようにしています.Common JSとAMDモジュールは、これらのものを実行時にのみ確認できます.たとえば、Common JSモジュールは対象です.入力する時は対象属性を調べなければなりません.ES 6モジュールは対象ではなく、exportコマンドで明示的に出力コードを指定し、importコマンドで入力します.
    (2)基本文法
    exportコマンドは、モジュールの対外インターフェースを規定し、importコマンドは他のモジュールが提供する機能を入力するために使用されます.
    /**      **/
    var basicNum = 0;
    var add = function (a, b) {
         
        return a + b;
    };
    
    export {
          basicNum, add };
    
    /**      **/
    import {
          basicNum, add } from './math';
    
    function test(ele) {
         
        ele.textContent = add(99 + basicNum);
    }
    
    導出モジュールには、デフォルトで導出された書き方module.exportがあり得る.
    // export-default.js
    export default function () {
         
      console.log('foo');
    }
    
    //       ,           ,import                。
    // import-default.js
    import customName from './export-default'; 
    customName(); // 'foo'
    
    (2)ES 6モジュールとCommunJSモジュールの違い
    1.Common JSモジュールは運転時にロードし、ES 6モジュールはコンパイル時に出力インターフェースです.2.Common JSモジュールが出力するのは値のコピーで、ES 6モジュールが出力するのは値の参照です.
    差異一:Common JSがロードしたのは一つのオブジェクト(すなわちmodule.export属性)であり、このオブジェクトはスクリプトが実行されてからしか生成されないからです.ES 6モジュールはオブジェクトではなく、外部インターフェースは静的な定義であり、コード静的な解析段階で生成される.
    差異二:
    // export.js
    export let num = 5;
    export let incrementNum = function() {
         
      ++num;
    };
    
    // import.js
    import {
          num, num2, incrementNum } from '../export.js';
    
    console.log(num); // 5
    console.log(incrementNum());
    console.log(num); // 6
    
    上からES 6モジュール化は上のCommunJSとは違っています.ES 6モジュールは動的参照です.キャッシュ値はありません.モジュール内の変数はそのモジュールに結合されています.CommunJSは値のコピー(元のタイプ)を入力しています.関数、オブジェクトであれば、参照用です.
    三、まとめ
  • Common JS仕様は主にサービスエンドプログラミングに使われています.ロードモジュールは同期しています.これはブラウザ環境には適合していません.同期ということは、ローディングをブロックすることを意味しています.ブラウザリソースは非同期的にローディングされていますので、AMD CMDソリューションがあります.
  • AMD仕様は、ブラウザ環境において、非同期的にモジュールをロードし、複数のモジュールを並列にロードすることができる.しかし、AMD規格の開発コストが高く、コードの読みと書きが難しく、モジュール定義方式の意味がスムーズではない.
  • CMD仕様はAMD仕様と似ています.いずれもブラウザのプログラミングに使われています.近いところに依存して、遅延実行しています.Node.jsで実行しやすいです.ただし、SPMパッケージに依存して、モジュールのロードロジックは
  • に偏っています.
  • ES 6は言語標準のレベルでモジュール機能を実現し、しかもかなり簡単に実現され、CommonJSとAMD仕様を完全に代替でき、ブラウザとサーバー共通のモジュールソリューションになります.
  • 参考文献
    フロントエンドモジュール化の詳細解(完全版)Javascriptモジュール化プログラミング(二):AMD規範CMDモジュール定義規範JavaSriptモジュール仕様-AMD仕様とCMD仕様の紹介