模塊化可以使你的代碼低耦合,功能模塊直接不相互影響。
模仿塊級(jí)作用域
JS中沒有塊級(jí)作用域,而是函數(shù)作用域,函數(shù)中聲明的變量和函數(shù)不會(huì)泄露到外部作用域。那么就可以通過在函數(shù)中創(chuàng)建私有變量。
function f() {
var a = 1;
}
a // ReferenceError: a is not defined
但是這樣函數(shù)名也是一個(gè)全局變量,也有污染全局變量的危險(xiǎn)。那么如果使用匿名函數(shù)呢?
// 這樣會(huì)報(bào)錯(cuò),函數(shù)聲明必須要有標(biāo)識(shí)符
function () {
var a = 1;
}
// 仍是會(huì)生成全局標(biāo)識(shí)符
var f = function () {
var a = 1;
}
JS中可以利用立即執(zhí)行函數(shù)模仿塊級(jí)作用域,立即函數(shù)是一個(gè)函數(shù)表達(dá)式而不是函數(shù)聲明,不會(huì)提升,解析到這行就會(huì)立即運(yùn)行。這樣既不會(huì)污染全局變量,函數(shù)也可以執(zhí)行。
// 寫法一
(function () {
// 塊級(jí)作用域
}());
// 寫法二
(function () {
// 塊級(jí)作用域
})();
// 寫法三
(function (fn) {
fn();
})(function f() {
// 塊級(jí)作用域
});
私有變量
JS中函數(shù)的參數(shù)、局部變量和函數(shù)內(nèi)部定義的函數(shù)都不能再函數(shù)的外部被訪問,所以被稱為私有變量。
那么有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為特權(quán)方法。
特權(quán)方法是在對(duì)象上創(chuàng)建,一般有兩種方式:構(gòu)造函數(shù)定義特權(quán)方法和靜態(tài)私有變量實(shí)現(xiàn)特權(quán)方法。這兩種都是用于為自定義類型創(chuàng)建私有變量和特權(quán)方法的。
-
構(gòu)造函數(shù)定義特權(quán)方法;
function F() { var a = 1; // 私有變量 function sayA() { // 私有函數(shù) console.log(a); } this.sayA = sayA; // 特權(quán)方法 } var f = new F(); f.sayA(); // 1
缺點(diǎn)是每個(gè)實(shí)例都會(huì)創(chuàng)建一組新方法,違反了構(gòu)造函數(shù)與實(shí)例對(duì)象相分離的原則。并且,非常耗費(fèi)內(nèi)存。
-
靜態(tài)私有變量實(shí)現(xiàn)特權(quán)方法;
(function () { var a = 1; // 私有變量 function sayA() { // 私有函數(shù) console.log(a); } // 構(gòu)造函數(shù)使用函數(shù)表達(dá)式,且不使用var,函數(shù)聲明只能創(chuàng)建局部變量,不使用var的函數(shù)表達(dá)式可以創(chuàng)建全局變量,讓其在私有作用域之外訪問 F = function () { // }; F.prototype.sayA = sayA; // 特權(quán)方法 })(); var f = new F(); f.sayA(); // 1
缺點(diǎn)是私有變量是公用的,所有實(shí)例使用的都是相同的私有變量。
模塊模式
模塊模式是為單例創(chuàng)建私有變量和特權(quán)方法。
在JS可以利用立即執(zhí)行函數(shù)和閉包創(chuàng)建模塊。
模塊模式需要具備兩個(gè)必要條件:
必須有外部的封閉函數(shù), 該函數(shù)必須至少被調(diào)用一次( 每次調(diào)用都會(huì)創(chuàng)建一個(gè)新的模塊實(shí)例);
-
封閉函數(shù)必須返回至少一個(gè)內(nèi)部函數(shù), 這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包, 并且可以訪問或者修改私有的狀態(tài);
var f = function () {
var a = 1; // 私有變量
return { // 函數(shù)調(diào)用后返回一個(gè)包含公開屬性和方法的對(duì)象
sayA: function () { // 特權(quán)方法,通過閉包可以在外部調(diào)用時(shí)訪問內(nèi)部私有變量
console.log(a);
}
}
};
f().sayA(); // 1
利用匿名函數(shù)自執(zhí)行改寫
var f = (function () {
var a = 1; // 私有變量
return { // 函數(shù)調(diào)用后返回一個(gè)包含公開屬性和方法的對(duì)象
sayA: function () { // 特權(quán)方法,通過閉包可以在外部調(diào)用時(shí)訪問內(nèi)部私有變量
console.log(a);
}
}
})();
f.sayA(); // 1