JavaScript設(shè)計模式之單例模式詳解
什么是單例模式
單,單個;例,實例。顧名思義,單例設(shè)計模式就是限制一個類必須只能有一個類,如果第二次創(chuàng)建的時候,我們可以拋出錯誤或者返回第一次的實例。
我們知道當new一個構(gòu)造函數(shù)時就會得到一個實例對象,new
的執(zhí)行原理如下:
function Person() { // let obj = { // 1 // name: 'Tom' // 3的效果 // } // Person.call(obj) // 2 讓Person構(gòu)造函數(shù)的this指向obj // obj.__proto__ = Person.prototype // 4 //讓實例對象的隱式原型等于構(gòu)造函數(shù)的顯示原型 // return obj // 5 返回實例對象 this.name = 'Tom' // 3 往obj上添加屬性 let p1 = new Person() let p2 = new Person() console.log(p1 === p2);//false }
當使用 new
關(guān)鍵字創(chuàng)建一個對象時,每次都會生成一個新的實例,這意味著每個對象都有自己獨立的內(nèi)存空間和引用地址。因此,即使兩個對象是由同一個類或構(gòu)造函數(shù)創(chuàng)建的,它們的引用地址也是不同的。
而單例模式就是要我們不管new多少次,都得到相同的這個對象。
實現(xiàn)方法
一、采用static靜態(tài)方法
靜態(tài)方法在類本身上定義,不依賴于類的實例。所以靜態(tài)方法只能被類訪問,不能被實例對象訪問
全局訪問:靜態(tài)方法提供了一個類級別的全局訪問點,可以在不實例化類的情況下調(diào)用。
實例管理:靜態(tài)方法可以操作靜態(tài)屬性來存儲和管理唯一實例,從而確保實例的唯一性。
示例代碼
class Person { constructor() { this.name = 'Tom' //初始化name屬性 } static getInstance() {//靜態(tài)方法,用于創(chuàng)建或獲取 Person的唯一實例 if (!Person.instance) {//如果不存在,則創(chuàng)建一個新的 實例 Person.instance = new Person() } return Person.instance//將其賦值給Person.instance } } let p1 = Person.getInstance() let p2 = Person.getInstance() console.log(p1 === p2)//true
二、閉包
1. 閉包的基本概念
閉包是一個函數(shù)和其相關(guān)的詞法環(huán)境的組合,這個環(huán)境包含了該函數(shù)的作用域中的所有變量。
在JavaScript中,閉包允許函數(shù)訪問其外部作用域中的變量,即使函數(shù)在外部作用域之外被調(diào)用時,也可以保留對這些變量的訪問權(quán)限。
2. 單例模式的需求
單例模式需要以下特性:
- 唯一實例:保證類在整個應(yīng)用程序中只有一個實例。
- 全局訪問:提供一個全局訪問點來獲取這個唯一實例。
3. 使用閉包實現(xiàn)單例模式
閉包可以通過封裝實例的創(chuàng)建和管理邏輯來實現(xiàn)單例模式。具體來說,閉包可以幫助我們創(chuàng)建一個私有作用域來保存唯一實例,從而控制實例的唯一性。
示例代碼
class Person { constructor() { this.name = 'Tom' } static getInstance() { let instance = null return function() { if (!instance) { instance = new Person() } return instance } } } const simple = Person.getInstance() let p1 = simple() let p2 = simple() console.log(p1 === p2);
這段代碼中關(guān)于閉包的使用:
- 每次調(diào)用返回的匿名函數(shù)時,閉包會記住
instance
變量的值。 - 如果
instance
為null
,則創(chuàng)建一個新的Person
實例,并將其賦值給instance
變量。 - 如果
instance
已經(jīng)存在,則直接返回這個實例。 - 閉包創(chuàng)建了一個私有作用域,在這個作用域內(nèi)管理
instance
變量,使其不會被外部代碼直接訪問或修改。這確保了只有一個實例能夠被創(chuàng)建,并且所有對該實例的訪問都通過同一個方法。
應(yīng)用場景
這里我們用一段 HTML 進行簡單演示,展示如何通過單例模式來管理瀏覽器的 localStorage
數(shù)據(jù)存取。在某些場景下,我們需要確保對 localStorage
的操作是由同一個實例來執(zhí)行的,避免重復創(chuàng)建對象,確保數(shù)據(jù)的一致性。
<body> <button id="save">存儲</button> <button id="get">取值</button> <script> let save = document.getElementById('save') let get = document.getElementById('get') // 定義一個Storage類,用單例模式封裝LocalStorage操作 class Storage { // 使用靜態(tài)方法實現(xiàn)單例模式 static getInstance() { if (!Storage.instance) { Storage.instance = new Storage(); } return Storage.instance; } // 獲取LocalStorage中的數(shù)據(jù) getItem(key) { return localStorage.getItem(key); } // 存儲數(shù)據(jù)到LocalStorage setItem(key, val) { return localStorage.setItem(key, val); } } // 獲取唯一的Storage實例 const storage = Storage.getInstance(); const storage2 = Storage.getInstance(); // 點擊存儲按鈕,保存數(shù)據(jù)到LocalStorage save.onclick = function() { storage.setItem('name', '高老師'); } // 點擊取值按鈕,彈出LocalStorage中的數(shù)據(jù) get.onclick = function() { alert(storage2.getItem('name')); } </script> </body> </html>
代碼解讀
HTML 結(jié)構(gòu):
頁面中包含兩個按鈕,分別用于“存儲”和“取值”操作。通過id
獲取按鈕元素,并綁定相應(yīng)的點擊事件。Storage 類的定義:
Storage
類封裝了對localStorage
的操作,并通過靜態(tài)方法getInstance
實現(xiàn)單例模式。這個方法確保Storage
類在整個應(yīng)用中只有一個實例,這樣對localStorage
的訪問都是通過同一個對象進行的。按鈕事件處理:
- 點擊“存儲”按鈕時,
Storage
實例的setItem
方法將'高老師'
存儲在localStorage
中,鍵名為'name'
。 - 點擊“取值”按鈕時,
Storage
實例的getItem
方法讀取localStorage
中存儲的'name'
,并通過彈窗顯示出來。
- 點擊“存儲”按鈕時,
結(jié)果驗證
在這段代碼中,無論你點擊多少次“存儲”或“取值”按鈕,所有的操作都會通過同一個 Storage
實例進行。這保證了數(shù)據(jù)的一致性,并且利用單例模式避免了不必要的對象創(chuàng)建。
應(yīng)用優(yōu)勢
通過這種封裝方式,我們可以更方便地管理和擴展與 localStorage
相關(guān)的操作,同時避免了全局狀態(tài)的混亂。此外,單例模式的使用確保了在整個應(yīng)用程序中,只會存在一個 Storage
實例,簡化了管理,減少了內(nèi)存消耗。
以上就是JavaScript設(shè)計模式之單例模式詳解的詳細內(nèi)容,更多關(guān)于JavaScript單例模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js判斷當頁面無法回退時關(guān)閉網(wǎng)頁否則就history.go(-1)
當頁面沒有前驅(qū)歷史記錄時,點擊返回按鈕時直接關(guān)閉頁面,否則就退回到前一頁2014-08-08用JS寫一段判斷搜索引擎來路并且屏蔽PC的跳轉(zhuǎn)代碼
以下是用JS寫的判斷搜索引擎來路并屏蔽PC跳轉(zhuǎn)的代碼,需要的朋友可以參考下2023-12-12JavaScript 節(jié)流函數(shù) Throttle 詳解
這篇文章主要為大家詳細介紹了JavaScript 節(jié)流函數(shù) Throttle,感興趣的小伙伴們可以參考一下2016-07-07