The Module Pattern,模塊模式,也譯爲模組模式,是一種通用的對代碼進行模塊化組織與定義的方式。這裏所說的模塊(Modules),是指實現某特定功能的一組方法和代碼。許多現代語言都定義了代碼的模塊化組織方式,好比 Golang 和 Java,它們都使用 package 與 import 來管理與使用模塊,而目前版本的 JavaScript 並未提供一種原生的、語言級別的模塊化組織模式,而是將模塊化的方法交由開發者來實現。所以,出現了不少種 JavaScript 模塊化的實現方式,好比,CommonJS Modules、AMD 等。 javascript
一、CommonJS 是一個有志於構建 JavaScript 生態圈的組織。整個社區致力於提升 JavaScript 程序的可移植性和可交換性,不管是在服務端仍是瀏覽器端。html
a group with a goal of building up the JavaScript ecosystem for web servers, desktop and command line apps and in the browser.前端
一個有目標的構建JavaScript生態系統Web服務器組,在瀏覽器和命令行應用程序和桌面。(他本身wiki上這麼說的)java
這個組織呢制定了一些規範 (能夠去他們網站看看 http://www.commonjs.org/)包括CommonJS Modules/1.0 規範,咱們平時所說的commonjs規範,說的就是這個了。node
「The CommonJS API will fill that gap by defining APIs that handle many common application needs, ultimately providing a standard library as rich as those of Python, Ruby and Java. 」--(出自 http://www.commonjs.org/)jquery
因此說Commonjs是一個更偏向於服務器端的規範。Node.js採用了這個規範。 根據CommonJS規範,一個單獨的文件就是一個模塊。加載模塊使用require方法,該方法讀 取一個文件並執行,最後返回文件內部的exports對象。git
他又說了,能夠用在下面這些場景 ,因此他更明顯的偏向服務器端。固然你也能夠把它用在瀏覽器裏邊(他們本身說能夠)。github
二、AMD規範web
Commonjs解決了模塊化的問題,而且能夠用在瀏覽器中,可是Commonjs是同步加載模塊,當要用到該模塊了,現加載現用,這種同步機制到了瀏覽器裏邊就有問題了,加載速度啊啥的(覽器同步加載模塊會致使性能、可用性、調試和跨域訪問等問題)。編程
鑑於瀏覽器的特殊狀況,又出現了一個規範,這個規範呢能夠實現異步加載依賴模塊,而且會提早加載那就是AMD規範。AMD能夠做爲CommonJS模塊一箇中轉的版本只要CommonJS沒有被用來同步的require調用。使用同步require調用的CommonJS代碼能夠被轉換爲使用回調風格的AMD模塊加載器(https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88) (它說的)。
下面是一個使用了簡單CommonJS轉換的模塊定義(它是amd規範的一種用法):
define(function (require, exports, module) { var a = require('a'), b = require('b'); exports.action = function () {}; });
因此說AMD和Commonjs是兼容的,只要稍稍調換一下調用方法就實現了同步加載(我很懷疑amd也是在commonjs基礎上加了個殼,而後並無找到其餘的神馬說明和支持的文字,找到了必定加到這)。
看一下AMD規範你會發現,AMD基本都是提早說明依賴模塊,而後預加載這些模塊,實際上這就要求你提早想好這些依賴,提早寫好,否則寫代碼過程當中要回到開頭繼續添加依賴。
三、CMD
不知道是否是針對這個問題,淘寶的玉伯大牛搞了個seajs出來,並聲稱這個規範是遵循CMD規範的,而後給出了這個規範的一個鏈接(打開會發現draft字樣)。關於這個規範呢玉伯在知乎是這麼說的
」AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
「
因此這個規範其實是爲了Seajs的推廣而後搞出來的。那麼看看SeaJS是怎麼回事兒吧,基本就是知道這個規範了。
一樣Seajs也是預加載依賴js跟AMD的規範在預加載這一點上是相同的,明顯不一樣的地方是調用,和聲明依賴的地方。AMD和CMD都是用difine和require,可是CMD標準傾向於在使用過程當中提出依賴,就是無論代碼寫到哪忽然發現須要依賴另外一個模塊,那就在當前代碼用require引入就能夠了,規範會幫你搞定預加載,你隨便寫就能夠了。可是AMD標準讓你必須提早在頭部依賴參數部分寫好(沒有寫好? 倒回去寫好咯)。這就是最明顯的區別。
AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
區別:
1. 對於依賴的模塊,AMD 是提早執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。CMD 推崇 as lazy as possible.
2. CMD 推崇依賴就近,AMD 推崇依賴前置。看代碼:
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此處略去 100 行
var b = require('./b') // 依賴能夠就近書寫
b.doSomething()
// ...
})
// AMD 默認推薦的是
define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()
...
})
雖然 AMD 也支持 CMD 的寫法,同時還支持將 require 做爲依賴項傳遞,但 RequireJS 的做者默認是最喜歡上面的寫法,也是官方文檔裏默認的模塊定義寫法。
3. AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。
CommonJS服務器端範疇,AMD,CMD客戶瀏覽器端範疇
當咱們寫一個文件須要兼容不一樣的加載規範的時候怎麼辦呢,看看下面的代碼。
(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD define(['jquery', 'underscore'], factory); } else if (typeof exports === 'object') { // Node, CommonJS之類的 module.exports = factory(require('jquery'), require('underscore')); } else { // 瀏覽器全局變量(root 即 window) root.returnExports = factory(root.jQuery, root._); } }(this, function ($, _) { // 方法 function a(){}; // 私有方法,由於它沒被返回 (見下面) function b(){}; // 公共方法,由於被返回了 function c(){}; // 公共方法,由於被返回了 // 暴露公共方法 return { b: b, c: c } }));
參考文檔
https://my.oschina.net/chenzhiqiang/blog/129783
RequireJS和AMD規範 http://javascript.ruanyifeng.com/tool/requirejs.html
知乎 AMD 和 CMD 的區別有哪些? http://www.zhihu.com/question/20351507