將一組模塊(及其依賴項)以正確的順序拼接到一個文件(或一組文件)中的過程。javascript
模塊是實現特定功能的一組屬性和方法的封裝。html
將模塊寫成一個對象,全部的模塊成員都放到這個對象裏面。java
var module1 = new Object({ _count:0, f1:function(){}, f2:function(){} }) module1.f1() module1.f2()
上面的對象能夠改變裏面的屬性和方法,不安全git
var module1 = (function(){ var count=0; return { f1:function(){}, f2:function(){}} }()); module1.f1() module1.f2() module1.count //undefined
使用 將相應的方法和屬性封裝在函數中,這樣就不會暴露私有成員es6
function Father (){ var arr =[]; this.add = function (val){ arr.push(val) } this.toString = function(){ return arr.join(''); } } var a = new Father(); a.add(1);//[1] a.toString();//"1" a.arr // undefined
上面的函數將 arr
變成私有變量,在函數外部沒法訪問,可是造成了閉包,很是耗費內存;
違背了構造函數與實例對象在數據上相分離的原則(即實例對象的數據,不該該保存在實例對象之外)。github
function ToString() { this._buffer = []; } ToString.prototype = { constructor: ToString, add: function (str) { this._buffer.push(str); }, toString: function () { return this._buffer.join(''); } };
雖然上面的構造函數未生成閉包,可是外部能夠修改方法和屬性,不安全數組
若是一個模塊很大或者一個模塊須要繼承另外一個模塊能夠利用當即執行函數的特效來封裝瀏覽器
var module1 = (function(m1){ mod1.col=function(){ console.log(this) }; return mod1; }(window.modlue2 ||{})) //有些模塊多是null 確保函數正常執行 採用兼容模式 window.modlue2 ||{}
var module1 = (function ($, Swiper) { //... }(jQuery, Swiper));
上面的 module1 引入 jQuery 和 Swiper 當作兩個參數傳入模塊中,保證了模塊的獨立性,還使得模塊之間的依賴關係變得明顯。緩存
當即執行函數還能夠起到命名空間的做用。安全
(function($, window, document) { function go(num) { } function handleEvents() { } function initialize() { } function dieCarouselDie() { } //attach to the global scope window.finalCarousel = { init : initialize, destroy : dieCarouselDie } }( jQuery, window, document ));
以上都有一個共同點:使用單個全局變量箭頭代碼包裝在函數中,使用閉包創建私有空間
可是都有缺點:
CommonJS
是一種思想, 本質上是可複用的JavaScript,它導出特定的對象,提供其它程序使用。
因爲 JavaScript
沒有模塊系統、標準庫較少、缺少包管理工具,所以CommonJS
是爲它的表現來制定規範。
每一個JavaScript 文件 都將模塊存儲在本身獨有的做用域中。
須要使用 module.exports
和 exports.obj
來導出對象,並在須要它的程序中使用 require('module')
加載
//文件1 function myModule() { this.hello = function() { return 'hello!'; } this.goodbye = function() { return 'goodbye!'; } } module.exports = myModule; //文件2 var myModule = require('myModule'); var myModuleInstance = new myModule(); myModuleInstance.hello(); // 'hello!' myModuleInstance.goodbye(); // 'goodbye!'
var module1 = { export1:{} }; (function (module,exports){ exports.add = functon(val){ return val *10 } }(module1,module1.export1)); var fn = module1.export1.add; fn(2)//20
利用當即執行函數 接受兩個參數 module 和 exports, 模塊就經過當即執行函數賦值,而後導出模塊,便可實現模塊的加載
這種方法的好處:
CommonJS
採用服務器優先方法而且同步加載模塊,所以在瀏覽器中使用它會阻止瀏覽器運行其餘內容,直到加載完成。咱們可使用 AMD
來異步加載
define
,經過 define
方法定義模塊。define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) { console.log(myModule.hello()); });
上面的 define
函數將每一個模塊的依賴項,以數組的形式做爲參數。
這些依賴項會在後臺異步加載,一旦加載完成,
define
函數就調用模塊給出的回調函數
myModule
可能像下面同樣定義:
define([], function() { return { hello: function() { console.log('hello'); }, goodbye: function() { console.log('goodbye'); } }; });
CMD
由玉伯大佬提出並用於SeaJSCMD和AMD 不一樣點:
define(function(require, exports, module) { var near = require('./a') near.doSomething() // 此處略去 100 行 var nearOne = require('./b') // 依賴能夠就近書寫 nearOne.doSomething() // ... })
define(['./a', './b'], function(nearTow, nearThree) { // 必須一開始加載 nearTow.doSomething() // 此處略去 100 行 nearThree.doSomething() ... })
CMD
裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。 AMD
的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。AMD
和 CommonJS
不一樣點:AMD
:
CommonJS
:
UMD
同時支持
AMD
和CommonJS
本質 建立了一種方法來使用二者的任何一種,同時支持全局變量定義,(JS兼容性的經常使用思想)因此UMD
能夠在客戶端和服務器上工做
(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD define(['myModule', 'myOtherModule'], factory); } else if (typeof exports === 'object') { // CommonJS module.exports = factory(require('myModule'), require('myOtherModule')); } else { root.returnExports = factory(root.myModule, root.myOtherModule); } }(this, function (myModule, myOtherModule) { function notHelloOrGoodbye(){}; function hello(){}; function goodbye(){}; return { hello: hello, goodbye: goodbye } }));
import
關鍵字引入模塊,經過 export
關鍵字導出模塊//a.js export let cun =1; export function add() { cun++; } //---------------- import { cun, add } from './a.js'; console.log(cun); // 1 incCounter(); console.log(cun); // 2 export var fo ='a'; setTimeout(() => fo ='b',500); import {fo} from './a.js'; console.log(fo);//'a' setTimeout(()=> console.log(fo),500)//'b' //ES6 輸入的模塊變量,只是一個「符號鏈接」,因此這個變量是隻讀的,對它進行從新賦值會報錯。 fo = 's' //error
CommonJS
、AMD
和CMD
相比:ES6
模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。// lib/counter.js var counter = 1; function increment() { counter++; } function decrement() { counter--; } module.exports = { counter: counter, increment: increment, decrement: decrement }; // src/main.js var counter = require('../../lib/counter'); counter.increment(); console.log(counter.counter); // 1