在其餘高級語言中,都有模塊中這個概念,好比java的類文件,PHP有include何require機制,JS一開始就沒有模塊這個概念,起初,js經過<script>標籤引入代碼的方式顯得雜亂無章,語言自身也缺少組織和約束能力,因此人們不得不以各類命名空間等方式認爲的約束代碼,達到安全易用的目的。經歷十幾年的發展,js也執行起了響應的規範,commonJS規範的提出算是一個重要的里程碑。javascript
1、commonJS規範html
commonJS規範的願景是但願JavaScript能在任何地方上運行,出發點主要是想彌補起初沒有模塊系統、標準庫較少、沒有標準接口,缺少包管理器等缺陷,但願JavaScript能夠具有和java等語言具有的開發大型應用能力的能力。它爲JavaScript開發大型應用程序指明瞭一條很是好的道路,node正是借鑑這個的規範慢慢的出如今人們的視野中,且逐漸變得強大。前端
commonJS對模塊的定義十分簡單,主要分爲模塊引用、模塊定義、模塊標識幾個部分。java
根據這個規範,每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數都是私有的,對其餘文件不可見。這個規加載的模塊是同步的,加載完成才能執行後面的操做。node
該規範主要是經過 module.exports向外提供接口,加載某個模塊,實際上是加載該模塊的module.exports屬性。c++
//test1.js 模塊文件 var a=10; var dosomething = function(){ /**代碼**/ }
//模塊定義 module.exports.a = a; module.exports.dosomething = dosomething; var test2 = require('./test1.js'); //模塊引用 其中./test1.js就是模塊標識 console.log(test1.a); console.log(test1.dpsomething());//調用test1完成以後,就能夠去使用test1所暴露出來的接口(變量)
特色:git
一、全部代碼都運行在模塊做用域,不會污染全局做用域。github
二、模塊能夠屢次加載,可是隻會在第一次加載時運行一次,而後運行結果就被緩存了,之後再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。後端
三、模塊加載的順序,按照其在代碼中出現的順序。瀏覽器
四、便於服務器端和桌面應用使用。
缺點:
由於該規範加載模塊是同步的,瀏覽器獲取一個資源是經過發送http請求以後得到的,這意味着會出現阻塞加載,從而在瀏覽器進程出現假死現象。因此瀏覽器須要的是異步加載的規範,這這是下面所講的AMD和CMD規範。
2、node模塊
node在實現模塊的實現中並不是徹底按照commonJS規範實現,而是對上面模塊規範作了必定的取捨,同時也增長了自身須要的特性。node在實現exports、require、module主要經歷幾個過程
一、路徑分析 二、文件定位 三、編譯執行
node中的模塊主要分爲兩類,一類是nodet提供的核心模塊,如fs 、http等模塊; 一類是用戶編寫的文件模塊。
核心模塊在node代碼編譯的過程當中,編譯成了二進制執行文件,在node進程啓動時候,部分核心模塊被加載進內存中,因此核心模塊在引入時候,文件定位和編譯執行能夠省略掉,並在路徑分析中被優先判斷,因此加載的速度是十分快的。
幾個特色
一、優先從緩存中加載
node對引入的模塊都會進行緩存,減小二次開銷。和瀏覽器緩存靜態腳本不同的是,瀏覽器緩存的是文件,node緩存的是編譯和執行以後的文的對象。因此require()方法對相同的模塊一概採用緩存優先的策略。
二、核心模塊是有c/c++和JavaScript編寫部分,c/c++在node目錄下的src下,JavaScript在lib目錄下。編譯的過程是講JavaScript模塊文件編譯成c/c++代碼,在引入核心模塊的過程當中,對模塊代碼進行了從頭至尾的包裝,讓require、module、exports這些變量可以使用,最後執行和處處exports對象。
三、b包管理機制
node組織了自身的核心模塊,也使得第三方的文件模塊均可以有序的編寫和使用,可是在第三方模塊中,模塊之間散列在各地,不能相互應用,在模塊以外,包和NPM是講各類模塊聯繫起來的一種機制。
3、模塊的側重點
在JavaScript和node出現以後,一些模塊能夠在先後端實現公用,先後端的js分別擱置在HTTP的兩端,扮演的角色也不同,瀏覽器的js須要從服務器分發到多個客戶端執行,而服務端則是相同的代碼屢次執行,前者瓶頸在於寬帶,後者在於CPU和內存等資源,前者經過網路讀取,後者經過磁盤讀取速度顯而易見,因此node模塊引入幾乎是同步的,可是,若是前端的額代碼也是採用同步當時引用,這樣可能由於UI須要等待腳本的加載,這樣就會影響用戶的體驗,這樣commonJS的同步加載就不能知足前端的應用市場了,必須須要其餘的加載模式,這樣AMD和CMD就營運而生了。
4、AMD
AMD(asynchronous module define)異步加載定義,該規範是RequireJS 在推廣過程當中對模塊定義的規範化產出的,是commonJS的一個延伸。
AMD模塊須要define來肯定一個模塊,用require()加載模塊。而node中是隱士包裝的,他們的目的都是達到做用域的隔離,僅在須要的時候被引入。
異步的模塊加載不影響後面語句的執行,全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。
//定義模塊
define("c", ["a", "b"], function(a, b) { //c:模塊id a和b是模塊的依賴 都是可選的 a.dosomething(); //加載依賴模塊a完成以後執行回調 }); //用require加載模塊 require(['c'], function ( c) { // 這裏寫其他的代碼 c.doSomething(); });
5、CMD
通用模塊定義,該規範是SeaJS 在推廣過程當中對模塊定義的規範化產出的,有興趣能夠看《前端代碼模塊加載器之sea,js》。 和AMD很相似,
require, exports, module經過形參的形式傳遞給模塊,在須要模塊的時候,隨時調用require()去調用。
c是模塊的名稱,['a']是依賴項,這兩個可省略,通常是省略的。
define('c',['a'],function(require, exports, module) { // 模塊代碼 });
若是b模塊中想引用a模塊,只需require()就能夠了
define(function(require,exports,module){
var a = require('a')
});
6、AMD和CMD的區別
一、對於依賴模塊,AMD是依賴前置,CMD依賴就近
// AMD define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好 a.doSomething() /******代碼*******/ b.doSomething() ... }) // CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() /******代碼*******/ var b = require('./b') // 依賴能夠就近書寫 b.doSomething() // ... })
二、執行順序
AMD是提早執行,CMD是延遲執行
三、提供的API
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。
AMD 裏,require 分全局 require 和局部 require,都叫 require。
CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。
爲了更好理解不一樣模塊化開發理念,建議參考:RequireJs和seaJs的差異。
7、兼容多種模塊規範
爲了讓一個模塊可有運行在先後端,保持先後端的一致性,以下就是展現將test()方法定義到不一樣的環境中,它可以兼容node 、AMD、CMD及常規的瀏覽器中:
;(function(name, definition){ //檢測上下文環境是否是AMD或CMD var hasDefined = typeof defined == 'function', //檢測上下文環境是否是node hasExports =typeof module !=='undefined' && module.exports; if(hasDefined){ defined(definition); //AMD或CMD }else if( hasExports){ module.exports = definition(); //node }else{ this[name] = definition(); //將執行的結果掛在window變量中,瀏覽器中的this這指向window } })('test',function(){ var test = function(){} return test; })
簡潔點:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global))); }(this, (function (exports) { 'use strict'; //code })));