JavaScript設(shè)計(jì)模式之單例模式詳解
什么是單例模式
單,單個(gè);例,實(shí)例。顧名思義,單例設(shè)計(jì)模式就是限制一個(gè)類必須只能有一個(gè)類,如果第二次創(chuàng)建的時(shí)候,我們可以拋出錯(cuò)誤或者返回第一次的實(shí)例。
我們知道當(dāng)new一個(gè)構(gòu)造函數(shù)時(shí)就會(huì)得到一個(gè)實(shí)例對(duì)象,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 //讓實(shí)例對(duì)象的隱式原型等于構(gòu)造函數(shù)的顯示原型
// return obj // 5 返回實(shí)例對(duì)象
this.name = 'Tom' // 3 往obj上添加屬性
let p1 = new Person()
let p2 = new Person()
console.log(p1 === p2);//false
}
當(dāng)使用 new 關(guān)鍵字創(chuàng)建一個(gè)對(duì)象時(shí),每次都會(huì)生成一個(gè)新的實(shí)例,這意味著每個(gè)對(duì)象都有自己獨(dú)立的內(nèi)存空間和引用地址。因此,即使兩個(gè)對(duì)象是由同一個(gè)類或構(gòu)造函數(shù)創(chuàng)建的,它們的引用地址也是不同的。
而單例模式就是要我們不管new多少次,都得到相同的這個(gè)對(duì)象。
實(shí)現(xiàn)方法
一、采用static靜態(tài)方法
靜態(tài)方法在類本身上定義,不依賴于類的實(shí)例。所以靜態(tài)方法只能被類訪問,不能被實(shí)例對(duì)象訪問
全局訪問:靜態(tài)方法提供了一個(gè)類級(jí)別的全局訪問點(diǎn),可以在不實(shí)例化類的情況下調(diào)用。
實(shí)例管理:靜態(tài)方法可以操作靜態(tài)屬性來存儲(chǔ)和管理唯一實(shí)例,從而確保實(shí)例的唯一性。
示例代碼
class Person {
constructor() {
this.name = 'Tom' //初始化name屬性
}
static getInstance() {//靜態(tài)方法,用于創(chuàng)建或獲取 Person的唯一實(shí)例
if (!Person.instance) {//如果不存在,則創(chuàng)建一個(gè)新的 實(shí)例
Person.instance = new Person()
}
return Person.instance//將其賦值給Person.instance
}
}
let p1 = Person.getInstance()
let p2 = Person.getInstance()
console.log(p1 === p2)//true

二、閉包
1. 閉包的基本概念
閉包是一個(gè)函數(shù)和其相關(guān)的詞法環(huán)境的組合,這個(gè)環(huán)境包含了該函數(shù)的作用域中的所有變量。
在JavaScript中,閉包允許函數(shù)訪問其外部作用域中的變量,即使函數(shù)在外部作用域之外被調(diào)用時(shí),也可以保留對(duì)這些變量的訪問權(quán)限。
2. 單例模式的需求
單例模式需要以下特性:
- 唯一實(shí)例:保證類在整個(gè)應(yīng)用程序中只有一個(gè)實(shí)例。
- 全局訪問:提供一個(gè)全局訪問點(diǎn)來獲取這個(gè)唯一實(shí)例。
3. 使用閉包實(shí)現(xiàn)單例模式
閉包可以通過封裝實(shí)例的創(chuàng)建和管理邏輯來實(shí)現(xiàn)單例模式。具體來說,閉包可以幫助我們創(chuàng)建一個(gè)私有作用域來保存唯一實(shí)例,從而控制實(shí)例的唯一性。
示例代碼
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ù)時(shí),閉包會(huì)記住
instance變量的值。 - 如果
instance為null,則創(chuàng)建一個(gè)新的Person實(shí)例,并將其賦值給instance變量。 - 如果
instance已經(jīng)存在,則直接返回這個(gè)實(shí)例。 - 閉包創(chuàng)建了一個(gè)私有作用域,在這個(gè)作用域內(nèi)管理
instance變量,使其不會(huì)被外部代碼直接訪問或修改。這確保了只有一個(gè)實(shí)例能夠被創(chuàng)建,并且所有對(duì)該實(shí)例的訪問都通過同一個(gè)方法。
應(yīng)用場(chǎng)景
這里我們用一段 HTML 進(jìn)行簡單演示,展示如何通過單例模式來管理瀏覽器的 localStorage 數(shù)據(jù)存取。在某些場(chǎng)景下,我們需要確保對(duì) localStorage 的操作是由同一個(gè)實(shí)例來執(zhí)行的,避免重復(fù)創(chuàng)建對(duì)象,確保數(shù)據(jù)的一致性。
<body>
<button id="save">存儲(chǔ)</button>
<button id="get">取值</button>
<script>
let save = document.getElementById('save')
let get = document.getElementById('get')
// 定義一個(gè)Storage類,用單例模式封裝LocalStorage操作
class Storage {
// 使用靜態(tài)方法實(shí)現(xiàn)單例模式
static getInstance() {
if (!Storage.instance) {
Storage.instance = new Storage();
}
return Storage.instance;
}
// 獲取LocalStorage中的數(shù)據(jù)
getItem(key) {
return localStorage.getItem(key);
}
// 存儲(chǔ)數(shù)據(jù)到LocalStorage
setItem(key, val) {
return localStorage.setItem(key, val);
}
}
// 獲取唯一的Storage實(shí)例
const storage = Storage.getInstance();
const storage2 = Storage.getInstance();
// 點(diǎn)擊存儲(chǔ)按鈕,保存數(shù)據(jù)到LocalStorage
save.onclick = function() {
storage.setItem('name', '高老師');
}
// 點(diǎn)擊取值按鈕,彈出LocalStorage中的數(shù)據(jù)
get.onclick = function() {
alert(storage2.getItem('name'));
}
</script>
</body>
</html>
代碼解讀
HTML 結(jié)構(gòu):
頁面中包含兩個(gè)按鈕,分別用于“存儲(chǔ)”和“取值”操作。通過id獲取按鈕元素,并綁定相應(yīng)的點(diǎn)擊事件。Storage 類的定義:
Storage類封裝了對(duì)localStorage的操作,并通過靜態(tài)方法getInstance實(shí)現(xiàn)單例模式。這個(gè)方法確保Storage類在整個(gè)應(yīng)用中只有一個(gè)實(shí)例,這樣對(duì)localStorage的訪問都是通過同一個(gè)對(duì)象進(jìn)行的。按鈕事件處理:
- 點(diǎn)擊“存儲(chǔ)”按鈕時(shí),
Storage實(shí)例的setItem方法將'高老師'存儲(chǔ)在localStorage中,鍵名為'name'。 - 點(diǎn)擊“取值”按鈕時(shí),
Storage實(shí)例的getItem方法讀取localStorage中存儲(chǔ)的'name',并通過彈窗顯示出來。
- 點(diǎn)擊“存儲(chǔ)”按鈕時(shí),
結(jié)果驗(yàn)證
在這段代碼中,無論你點(diǎn)擊多少次“存儲(chǔ)”或“取值”按鈕,所有的操作都會(huì)通過同一個(gè) Storage 實(shí)例進(jìn)行。這保證了數(shù)據(jù)的一致性,并且利用單例模式避免了不必要的對(duì)象創(chuàng)建。
應(yīng)用優(yōu)勢(shì)
通過這種封裝方式,我們可以更方便地管理和擴(kuò)展與 localStorage 相關(guān)的操作,同時(shí)避免了全局狀態(tài)的混亂。此外,單例模式的使用確保了在整個(gè)應(yīng)用程序中,只會(huì)存在一個(gè) Storage 實(shí)例,簡化了管理,減少了內(nèi)存消耗。
以上就是JavaScript設(shè)計(jì)模式之單例模式詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript單例模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS實(shí)現(xiàn)拼音(字母)匹配漢字(姓名)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用JavaScript實(shí)現(xiàn)拼音(字母)匹配(搜索)漢字(姓名)的效果,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-04-04
基于Bootstrap 3 JQuery及RegExp的表單驗(yàn)證功能
這篇文章主要介紹了基于Bootstrap 3 JQuery及RegExp的表單驗(yàn)證功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02
JS技巧動(dòng)手實(shí)現(xiàn)紅包兔子雨效果示例詳解
這篇文章主要為大家介紹了JS技巧動(dòng)手實(shí)現(xiàn)紅包兔子雨效果示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
BootstrapTable與KnockoutJS相結(jié)合實(shí)現(xiàn)增刪改查功能【二】
這篇文章主要介紹了BootstrapTable與KnockoutJS相結(jié)合實(shí)現(xiàn)增刪改查功能【二】的相關(guān)資料,非常具有參考價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-05-05
用window.onerror捕獲并上報(bào)Js錯(cuò)誤的方法
這篇文章主要介紹了用window.onerror捕獲并上報(bào)Js錯(cuò)誤的方法,需要的朋友可以參考下2016-01-01
基于ts的動(dòng)態(tài)接口數(shù)據(jù)配置的詳解
這篇文章主要介紹了基于ts的動(dòng)態(tài)接口數(shù)據(jù)配置的詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
javascript實(shí)現(xiàn)隨機(jī)顯示星星特效
這篇文章主要介紹了javascript實(shí)現(xiàn)隨機(jī)顯示星星特效的相關(guān)資料,以一個(gè)完整實(shí)例形式較為詳細(xì)的分析了js實(shí)現(xiàn)隨機(jī)顯示星星特效的實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-01-01

