本篇文章為大家展示了如何理解JavaScript的設(shè)計模式,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
龍山網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站設(shè)計等網(wǎng)站項目制作,到程序開發(fā),運營維護。成都創(chuàng)新互聯(lián)公司2013年開創(chuàng)至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)公司。
10年的貢山網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。營銷型網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整貢山建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)從事“貢山網(wǎng)站設(shè)計”,“貢山網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。
今天我們就聊一下這三個設(shè)計模式
單例模式 / 組合模式 / 觀察者模式
· 什么是單例模式呢?
· 我們都知道,構(gòu)造函數(shù)可以創(chuàng)造一個對象
· 我們 new 很多次構(gòu)造函數(shù)就能得到很多的對象
· 單例模式: 就是使用構(gòu)造函數(shù)實例化的時候,不管實例化多少回,都是同一個對象
· 也就是一個構(gòu)造函數(shù)一生只能 new 出一個對象
· 也就是說,當(dāng)我們使用構(gòu)造函數(shù),每一次 new 出來的對象 屬性/功能/方法 完全一樣 的時候,我們把他設(shè)計成單例模式
· 單例模式的核心代碼很簡單
· 其實就是判斷一下,他曾經(jīng)有沒有 new 出來過對象
· 如果有,就還繼續(xù)使用之前的那個對象,如果沒有,那么就給你 new 一個
// 準(zhǔn)備一個構(gòu)造函數(shù)// 將來要 new 的function Person() {}// 準(zhǔn)備一個單例模式函數(shù)// 這個單例模式函數(shù)要把 Person 做成一個單例模式// 將來再想要 new Person 的時候只要執(zhí)行這個 singleton 函數(shù)就可以了function singleton () {
let instance;
if (!instance) { // 如果 instance 沒有內(nèi)容 // 來到這里,證明 instance 沒有內(nèi)容 // 給他賦值為 new Person instance = new Person()
}
// 返回的永遠都是第一次 new Person 的實例 // 也就是永遠都是一個實例 return instance}const p1 = singleton()const p2 = singleton()console.log(p1 === p2) // true
· 我們就用這個核心代碼簡單書寫一個 demo
// 這個構(gòu)造函數(shù)的功能就是創(chuàng)建一個 div,添加到頁面中function CreateDiv() {
this.div = document.createElement('div')
document.body.appendChild(this.div)}CreateDiv.prototype.init = function (text) {
this.div.innerHTML = text}// 準(zhǔn)備把這個 CreateDiv 做成單例模式// 讓 singleton 成為一個閉包函數(shù)const singleton = (function () {
let instance
return function (text) {
if (!instance) {
instance = new CreateDiv()
}
instance.init(text)
return instance
}})()singleton('hello') // 第一次的時候,頁面中會出現(xiàn)一個新的 div ,內(nèi)容是 hellosingleton('world') // 第二次的時候,不會出現(xiàn)新的 div,而是原先的 div 內(nèi)容變成了 world
· 組合模式,就是把幾個構(gòu)造函數(shù)的啟動方式組合再一起
· 然后用一個 ”遙控器“ 進行統(tǒng)一調(diào)用
class GetHome {
init () {
console.log('到家了')
}}class OpenComputer {
init () {
console.log('打開電腦')
}}class PlayGame {
init () {
console.log('玩游戲')
}}
· 上面幾個構(gòu)造函數(shù)的創(chuàng)造的實例化對象的 啟動方式 都一致
· 那么我們就可以把這幾個函數(shù)以組合模式的情況書寫
· 然后統(tǒng)一啟動
· 準(zhǔn)備一個 組合模式 的構(gòu)造函數(shù)
class Compose {
constructor () {
this.compose = []
}
// 添加任務(wù)的方法 add (task) {
this.compose.push(task)
}
// 一個執(zhí)行任務(wù)的方法 execute () {
this.compose.forEach(item => {
item.init()
})
}}
· 我們就用我們的組合模式構(gòu)造函數(shù)來吧前面的幾個功能組合起來
const c = new Compose()// 把所有要完成的任務(wù)都放在隊列里面c.add(new GetHome())c.add(new OpenComputer)c.add(new PlayGame)// 直接器動任務(wù)隊列c.execute()// 就會按照順序執(zhí)行三個對象中的 init 函數(shù)
· 觀察者模式,通常也被叫做 發(fā)布-訂閱模式 或者 消息模式
· 英文名稱叫做 Observer
· 官方解釋: 當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新,解決了主體對象與觀察者之間功能的耦合,即一個對象狀態(tài)改變給其他對象通知的問題
· 聽起來很迷糊,但是其實沒有很難
· 當(dāng)你想去書店買書,但是恰巧今天你要買的書沒有了
· 我們又不能總在書店等著,就把我們的手機留給店員
· 當(dāng)你需要的書到了的時候,他會打電話通知你,你去買了就好了
· 你買到數(shù)了以后,就告訴他,我買到了,那么以后再來了書就不會通知你了
· 上面的例子可能還不是很明確
· 但是 addEventListener 是一個我們都用過的東西
· 這個東西其實就是一個標(biāo)準(zhǔn)的 觀察者模式
btn.addEventListener('click', function () {
console.log('btn 被點擊了')})
· 上面這個就是有一個 無形的觀察者 再觀察著 btn 的一舉一動
· 當(dāng)這個 btn 被點擊的時候,就會執(zhí)行 對應(yīng)的函數(shù)
· 我們也可以多綁定幾個函數(shù)
· 說白了: 觀察者模式就是我們自己實現(xiàn)一個 addEventListener 的功能
· 只不過 addEventListaner 只有固定的一些事件,而且只能給 dom 元素綁定
· 而我們自己寫的可以隨便綁定一個事件名稱,自己選擇觸發(fā)時機而已
· 首先我們分析功能
· 我們要有一個觀察者(這里抽象為一個對象 {})
· 需要有一個屬性,存放消息的盒子(把你綁定的所有事件放在里面)
· 需要一個 on 方法,用于添加事件
· 需要一個 emit 方法,用于發(fā)布事件(觸發(fā))
· 需要一個 off 方法,把已經(jīng)添加的方法取消
const observer = {
message: {},
on: function () {},
emit: function () {},
off: function () {}}
· 我們把它寫成一個構(gòu)造函數(shù)的形式
class Observer {
constructor () {
this.message = {}
}
on () {}
emit () {}
off () {}}
· 現(xiàn)在,一個觀察者的雛形就出來了
· 接下來完善方法就可以了
· 先來寫 ON 方法
· 添加一個事件
· 我們的 on 方法需要接受 兩個參數(shù)
· 事件類型
· 事件處理函數(shù)
class Observer {
constructor () {
this.message = {}
}
on(type, fn) {
// 判斷消息盒子里面有沒有設(shè)置事件類型 if (!this.message[type]) {
// 證明消息盒子里面沒有這個事件類型 // 那么我們直接添加進去 // 并且讓他的值是一個數(shù)組,再數(shù)組里面放上事件處理函數(shù) this.message[type] = [fn]
} else {
// 證明消息盒子里面有這個事件類型 // 那么我們直接向數(shù)組里面追加事件處理函數(shù)就行了 this.message[type].push(fn)
}
}
emit () {}
off () {}}
· 接下來就是發(fā)布事件
· 也就是讓我們已經(jīng)訂閱好的事件執(zhí)行一下
· 同樣需要接受兩個參數(shù)
· 要觸發(fā)的事件類型
· 給事件處理函數(shù)傳遞的參數(shù)
class Observer {
constructor () {
this.message = {}
}
on(type, fn) {
// 判斷消息盒子里面有沒有設(shè)置事件類型 if (!this.message[type]) {
// 證明消息盒子里面沒有這個事件類型 // 那么我們直接添加進去 // 并且讓他的值是一個數(shù)組,再數(shù)組里面放上事件處理函數(shù) this.message[type] = [fn]
} else {
// 證明消息盒子里面有這個事件類型 // 那么我們直接向數(shù)組里面追加事件處理函數(shù)就行了 this.message[type].push(fn)
}
}
emit(type, ...arg) {
// 判斷你之前有沒有訂閱過這個事件 if (!this.message[type]) return
// 如果有,那么我們就處理一下參數(shù) const event = {
type: type,
arg: arg || {}
}
// 循環(huán)執(zhí)行為當(dāng)前事件類型訂閱的所有事件處理函數(shù) this.message[type].forEach(item => {
item.call(this, event)
})
}
off() {}}
· 最后就是移除事件
· 就是把已經(jīng)訂閱的事件處理函數(shù)移除掉
· 同樣需要接受兩個參數(shù)
· 要移除的事件類型
· 要移除的事件處理函數(shù)
class Observer {
constructor () {
this.message = {}
}
on(type, fn) {
// 判斷消息盒子里面有沒有設(shè)置事件類型 if (!this.message[type]) {
// 證明消息盒子里面沒有這個事件類型 // 那么我們直接添加進去 // 并且讓他的值是一個數(shù)組,再數(shù)組里面放上事件處理函數(shù) this.message[type] = [fn]
} else {
// 證明消息盒子里面有這個事件類型 // 那么我們直接向數(shù)組里面追加事件處理函數(shù)就行了 this.message[type].push(fn)
}
}
emit(type, ...arg) {
// 判斷你之前有沒有訂閱過這個事件 if (!this.message[type]) return
// 如果有,那么我們就處理一下參數(shù) const event = {
type: type,
arg: arg || {}
}
// 循環(huán)執(zhí)行為當(dāng)前事件類型訂閱的所有事件處理函數(shù) this.message[type].forEach(item => {
item.call(this, event)
})
}
off (type, fn) {
// 判斷你之前有沒有訂閱過這個事件 if (!this.message[type]) return
// 如果有我們再進行移除 for (let i = 0; i < this.message[type].length; i++) {
const item = this.message[type][i]
if (item === fn) {
this.message[type].splice(i, 1)
i--
}
}
}}
· 以上就是最基本的 觀察者模式
· 接下來我們就使用一下試試看
const o = new Observer()// 準(zhǔn)備兩個事件處理函數(shù)function a(e) {
console.log('hello')}function b(e) {
console.log('world')}// 訂閱事件o.on('abc', a)o.on('abc', b)// 發(fā)布事件(觸發(fā))o.emit('abc', '100', '200', '300') // 兩個函數(shù)都回執(zhí)行// 移除事件o.off('abc', 'b')// 再次發(fā)布事件(觸發(fā))o.emit('abc', '100', '200', '300') // 只執(zhí)行一個 a 函數(shù)了
上述內(nèi)容就是如何理解JavaScript的設(shè)計模式,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。