JavaScript利用閉包實現(xiàn)模塊化
利用閉包的強大威力,但從表面上看,它們似乎與回調(diào)無關。下面一起來研究其中最強大的一個:模塊。
function foo() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { console.log( something ); } function doAnother() { console.log( another.join( " ! " ) ); } }
正如在這段代碼中所看到的,這里并沒有明顯的閉包,只有兩個私有數(shù)據(jù)變量something和another,以及doSomething() 和doAnother() 兩個內(nèi)部函數(shù),它們的詞法作用域(而這就是閉包)也就是foo() 的內(nèi)部作用域。
接下來考慮以下代碼:
function CoolModule() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { alert( something ); } function doAnother() { alert( another.join( " ! " ) ); } return { doSomething: doSomething, doAnother: doAnother }; } var foo = CoolModule(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3
這個模式在JavaScript 中被稱為模塊。最常見的實現(xiàn)模塊模式的方法通常被稱為模塊暴露,這里展示的是其變體。我們仔細研究一下這些代碼。
首先,CoolModule() 只是一個函數(shù),必須要通過調(diào)用它來創(chuàng)建一個模塊實例。如果不執(zhí)行外部函數(shù),內(nèi)部作用域和閉包都無法被創(chuàng)建。其次,CoolModule() 返回一個用對象字面量語法{ key: value, ... } 來表示的對象。這個返回的對象中含有對內(nèi)部函數(shù)而不是內(nèi)部數(shù)據(jù)變量的引用。我們保持內(nèi)部數(shù)據(jù)變量是隱藏且私有的狀態(tài)??梢詫⑦@個對象類型的返回值看作本質(zhì)上是模塊的公共API。這個對象類型的返回值最終被賦值給外部的變量foo,然后就可以通過它來訪問API 中的屬性方法,比如foo.doSomething()。
從模塊中返回一個實際的對象并不是必須的,也可以直接返回一個內(nèi)部函數(shù)。jQuery 就是一個很好的例子。jQuery 和$ 標識符就是jQuery 模塊的公共API,但它們本身都是函數(shù)(由于函數(shù)也是對象,它們本身也可以擁有屬性)。
doSomething() 和doAnother() 函數(shù)具有涵蓋模塊實例內(nèi)部作用域的閉包( 通過調(diào)用CoolModule() 實現(xiàn))。當通過返回一個含有屬性引用的對象的方式來將函數(shù)傳遞到詞法作用域外部時,我們已經(jīng)創(chuàng)造了可以觀察和實踐閉包的條件。如果要更簡單的描述,模塊模式需要具備兩個必要條件。
1. 必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會創(chuàng)建一個新的模塊實例)。
2. 封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。
一個具有函數(shù)屬性的對象本身并不是真正的模塊。從方便觀察的角度看,一個從函數(shù)調(diào)用所返回的,只有數(shù)據(jù)屬性而沒有閉包函數(shù)的對象并不是真正的模塊。上一個示例代碼中有一個叫作CoolModule() 的獨立的模塊創(chuàng)建器,可以被調(diào)用任意多次,每次調(diào)用都會創(chuàng)建一個新的模塊實例。當只需要一個實例時,可以對這個模式進行簡單的改進來實現(xiàn)單例模式:
var foo = (function CoolModule() { var something = "cool"; var another = [1, 2, 3]; function doSomething() { alert( something ); } function doAnother() { alert( another.join( " ! " ) ); } return { doSomething: doSomething, doAnother: doAnother }; })(); foo.doSomething(); // cool foo.doAnother(); // 1 ! 2 ! 3
立即調(diào)用這個函數(shù)并將返回值直接賦值給單例的模塊實例標識符foo。
模塊也是普通的函數(shù),因此可以接受參數(shù):
function CoolModule(id) { function identify() { console.log( id ); } return { identify: identify }; } var foo1 = CoolModule( "foo 1" ); var foo2 = CoolModule( "foo 2" ); foo1.identify(); // "foo 1" foo2.identify(); // "foo 2"
模塊模式另一個簡單但強大的變化用法是,命名將要作為公共API 返回的對象:
var foo = (function CoolModule(id) { function change() { // 修改公共API publicAPI.identify = identify2; } function identify1() { alert( id ); } function identify2() { alert( id.toUpperCase() ); } var publicAPI = { change: change, identify: identify1 }; return publicAPI; })( "foo module" ); foo.identify(); // foo module foo.change(); foo.identify(); // FOO MODULE
通過在模塊實例的內(nèi)部保留對公共API 對象的內(nèi)部引用,可以從內(nèi)部對模塊實例進行修改,包括添加或刪除方法和屬性,以及修改它們的值。
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
- JS沙箱模式實例分析
- JavaScript 設計模式 安全沙箱模式
- JavaScript的模塊化:封裝(閉包),繼承(原型) 介紹
- JS面向?qū)ο蠡A講解(工廠模式、構造函數(shù)模式、原型模式、混合模式、動態(tài)原型模式)
- js面向?qū)ο笾R妱?chuàng)建對象的幾種方式(工廠模式、構造函數(shù)模式、原型模式)
- JavaScript設計模式之觀察者模式(發(fā)布者-訂閱者模式)
- JavaScript 設計模式之組合模式解析
- javascript 設計模式之單體模式 面向?qū)ο髮W習基礎
- javascript設計模式之解釋器模式詳解
- 常用的Javascript設計模式小結
- JavaScript設計模式之工廠方法模式介紹
- JS實現(xiàn)閉包中的沙箱模式示例
相關文章
js如何監(jiān)聽input輸入事件及使用防抖封裝函數(shù)處理方法
這篇文章主要給大家介紹了關于js如何監(jiān)聽input輸入事件及使用防抖封裝函數(shù)處理方法的相關資料,最近有一個需求,需要我們實時監(jiān)聽input輸入框中的內(nèi)容,從而帶來更好的用戶體驗,需要的朋友可以參考下2023-07-07