前端模塊規範:AMD規範、CMD規範、CommonJS規範、ES6 Module

CommonJS規範

CommonJS對模塊的定義主要分爲模塊引用、模塊定義和模塊標識3個部分。
1、模塊引用
模塊引用的示例代碼如下:

var math = require('math');

在CommonJS規範中,存在require()方法,這個方法接受模塊標識,以此引入一個模塊的API到當前上下文中。

2、模塊定義
在模塊中,上下文提供require()方法來引入外部模塊。對應引入的功能,上下文提供了exports對象用於導出當前模塊的方法或者變量,並且它是唯一導出的出口。在模塊中,還存在一個module對象,它代表模塊自身,而exports是module的屬性。在Node中,一個文件就是一個模塊,將方法掛載在exports對象上作爲屬性即可定義導出的方式:

// math.js
exports.add = function () {
  var sum = 0,
    i = 0,
    args = arguments,
    l = args.length;
  while (i < l) {
    sum += args[i++];
  }
  return sum;
};

在另一個文件中,我們通過require()方法引入模塊後,就能調用定義的屬性或方法了:

// program.js
var math = require('math');
exports.increment = function (val) {
  return math.add(val, 1);
};

模塊標識
模塊標識其實就是傳遞給require()方法的參數,它必須是符合小駝峯命名的字符串,或者以’.’、’..'開頭的相對路徑,或者絕對路徑。它可以沒有文件名後綴.js。
它的意義在於將類聚的方法和變量等限定在私有的作用域中,同時支持引入和導出功能以順暢地連接上下游依賴。

AMD規範

AMD規範的全稱是“Asychronous Module Definition”,即“異步模塊定義”。

它的模塊定義如下:

define(id?,  dependencies?, factory);

其中模塊id和依賴是可選的,factory的內容就是實際代碼的內容。
如:

define(function() {
  var exports = {};
  exports.sayHello = function() {
    alert('Hello from module: ' + module.id);
  };
  return exports;
});

和CommonJS不同之處在於AMD模塊需要define來明確定義一個模塊(Node是隱式包裝),目的是進行作用域隔離,僅在需要的時候被引入,避免掉全局變量污染和不小心被修改;
另一個區別是內容需要通過返回值的方式實現導出。

AMD規範需要再聲明模塊的時候指定所有依賴,通過形參傳到模塊內容中。

define(['dep1', 'dep2'], function (dep1, dep2) {
	return function() {};
})

CDM規範

和AMD規範的主要區別在於定義模塊和依賴引入的部分。
CMD支持動態引入。

define (function(require, export , module) {
	// 模塊代碼
}

require,exports, module通過形參傳遞給模塊,在需要依賴模塊時,隨時調用require()引入即可(更接近CommomJS)

define(function(require, exports) {

  // 同步獲取模塊 a 的接口
  var a = require('./a');

  // 調用模塊 a 的方法
  a.doSomething();

// 異步加載多個模塊,在加載完成時,執行回調
  require.async(['./b', './c'], function(b, c) {
    b.doSomething();
    c.doSomething();
  });
});

注意
require 是同步往下執行,require.async 則是異步回調執行。require.async 一般用來加載可延遲異步加載的模塊。

如何兼容多種模塊規範

以hello()方法定義到不同運行環境中,兼容Node、AMD、CMD以及常見的瀏覽器環境中:

;(function (name, definition) {
  // 檢測上下文環境是否爲AMD或CMD
  var hasDefine = typeof define === 'function',
    // 檢查上下文環境是否爲Node
    hasExports = typeof module !== 'undefined' && module.exports;

  if (hasDefine) {
    // AMD環境或CMD環境
    define(definition);
  } else if (hasExports) {
    // 定義爲普通Node模塊
    module.exports = definition();
  } else {
    // 將模塊的執行結果掛在window變量中,在瀏覽器中this指向window對象
    this[name] = definition();
  }
})('hello', function () {
  var hello = function () {};
  return hello;
});

總結

AMD和require.js

AMD是“異步模塊定義”,瀏覽器模塊開發的規範。
特點:

  • 實現js文件的異步加載(避免加載時網頁失去響應);
  • 聲明模塊時需要先指定依賴,推崇依賴前置,提前執行
define(['dep1', 'dep2'], function (dep1, dep2) {
	return function() {};
})

RequireJS核心原理是什麼?(如何動態加載的?如何避免多次加載的?如何緩存的?)
RequireJS是基於AMD模塊加載規範,使用回調函數來解決模塊加載問題。
動態加載原理:RequireJS是使用創建script元素, 通過指定script元素的src屬性來實現加載模塊的。
特點
實現js文件的異步加載(避免加載時網頁失去響應);
管理模塊直接的依賴,便於代碼的編寫和維護。

CMD和sea.js

CMD是“通用模塊”定義。瀏覽器模塊開發的規範。
CMD推崇依賴就近、延遲執行
AMD和CMD區別是:AMD是依賴提前定義;CMD是使用的時候再require。
自身可以

CommonJS和Node.js

CommonJS是服務器端模塊的規範,Node.js採用了這個規範。
CommonJS規範一個單獨的文件就是一個模塊,加載模塊使用require方法,該方法讀取一個文件並執行。最後返回文件內部的exports對象。
CommonJS是同步加載模塊的。所以只有加載完才能繼續後面的操作。
Node.js主要是服務端編程,所以加載的模塊一般存於本地磁盤,加載起來比較快,不用考慮異步加載的方式。

ES6 Module

ES6在語言的標準上實現模塊功能,而且實現的很簡單,
ES6模塊功能主要由兩個命令構成:export和import。export命令用於規定模塊的對外接口,import命令用於輸入其他模塊提供的功能。
ES6的設計思想,是儘量靜態化,使得編譯時就可以確認模塊的依賴關係,以及輸入和輸出的變量。
ES6模塊不是對象,而是通過export命令顯示指定輸出的代碼,輸入也使用靜態命令的形式。
ES6 Module可以在編譯時就完成模塊編譯,效率比CommonJS要高。

發佈了23 篇原創文章 · 獲贊 16 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章