JavaScript中的模塊化
將代碼組織到一個類中的重要原因是,讓代碼更加“模塊化”,可以實現重用。但類不是唯一的方式。
模塊化的目標是支持大規模的程序開發,處理分散源中代碼的組裝,并且能讓代碼正確運行。很多前端框架包括了模塊系統,如DOJO,CommonJS,SeaJS,使用require函數。
1 類中的模塊
1.1 用做命名空間的對象
在模塊創建過程中避免污染全局變量的一種方法是使用一個對象作為命名空間。它將函數和值作為命名空間對象屬性存儲起來(可以通過全局變量引用),而不是定義全局函數和變量。如下例中的NotSet就有contains、toString、equals等方法。
// 可用做任何抽象方法
function abstractmethod() { throw new Error("abstract method"); }
function AbstractSet() {throw new Error("Can't instantiate abstract classes"); }
AbstractSet.prototype.contains = abstractmethod;
var NotSet = AbstractSet.extend(
function NotSet(set) {this.set = set;},
{
contains: function(x) {return !this.set.contains(x);},
toString: function(x) {return this.set.toString();},
equals: function(that) {
return that instanceof NotSet && this.set.equals(that.set);
}
}
)
基于“保持干凈的全局命名空間”的觀點,有一種更好的做法是將相似(功能相關)的類定義為一個單獨的全局對象:
var sets = {};
sets.NotSet = sets.AbstractSet.extend(...);
// 只有一個全局sets,通過它來調用
var s = new sets.NotSet(set);
// 更深層的命名空間
var sets = com.mrli.collections.sets;
用做私有命名空間的函數
有些輔助函數或方法,不需要對外調用,是私有對象(java中的private),不希望在外部是可訪問的。可以將模塊定義在某個函數的內部來實現。
例子1
var Set = (function invocation() { // 注意invocation并沒有全局創建對象,只是一個函數表達式,如果沒有invocation它就是一個匿名函數
function Set() { // 這個構造函數是局部變量
this.values = {}
this.n = 0;
tjhis.add.apply(this, arguments);
}
Set.prototype.contains = function(value) {
return this.values.hasOwnProperty(v2s(value));
}
// 內部函數,不用定義成_v2s,或者加set前綴,對外部不可見
function v2s(val) {
return val;
}
// 將Set從命名空間中導出
return Set;
} ()); // 這里的"()" 即執行前面定義的invocation函數,定義函數后立即執行
例子2:bootstrap源碼
bootstrap源碼
( https://github.com/twbs/bootstrap/blob/v4-dev/dist/js/bootstrap.js ),有如下方式:
第18行,使用了定義并立即執行的函數
第19,21行等,使用了內部函數
第36,189,3650行等,使用了立即執行的函數,不同的是傳入了jQuery
Bootstrap源碼1.png
Bootstrap源碼2.png
2 模塊化框架
目前有很多模塊化前端框架,如CommonJS、國產Sea.js等,它們更像是一種約定。尤其像angularjs1.x則是自帶模塊化功能,完全構建了自己的生態帝國。angularjs的出現,像是一個big
boom,可以說是震撼了前端圈。近年也涌現出了一大批優秀的前端,其中不乏國內的優秀框架,如React, vue, avalon等。
2.1 CommonJS(CMD)
2.2 Sea.js(AMD)
國產框架,創始人是淘寶前端玉伯