好程式設計師web前端培訓分享JavaScript學習筆記之設計模式

好程式設計師發表於2020-07-02

  好程式設計師web 前端培訓分享 JavaScript 學習筆記之設計模式, 設計模式是我們在  解決問題的時候針對特定問題給出的簡潔而最佳化的處理方案

   我們有很多的設計模式

   單例模式

   組合模式

   觀察者模式

   ...

   今天我們就聊一下這三個設計模式

   單例模式 / 組合模式 / 觀察者模式

單例模式

·  什麼是單例模式呢?

·  我們都知道,建構函式可以創造一個物件

·  我們 new 很多次建構函式就能得到很多的物件

·  單例模式: 就是使用建構函式例項化的時候,不管例項化多少回,都是同一個物件

·  也就是一個建構函式一生只能 new 出一個物件

·  也就是說,當我們使用建構函式,每一次 new 出來的物件 屬性/功能/方法  完全一樣  的時候,我們把他設計成單例模式

核心程式碼

·  單例模式的核心程式碼很簡單

·  其實就是判斷一下,他曾經有沒有 new 出來過物件

·  如果有,就還繼續使用之前的那個物件,如果沒有,那麼就給你 new 一個

// 準備一個建構函式 // 將來要 new 的 function   Person()   {} // 準備一個單例模式函式// 這個單例模式函式要把 Person 做成一個單例模式// 將來再想要 new Person 的時候只要執行這個 singleton 函式就可以了 function   singleton   ()   {

     let   instance;

     if   ( ! instance)   {   // 如果 instance 沒有內容          // 來到這裡,證明 instance 沒有內容          // 給他賦值為 new Person          instance   =   new   Person()

     }

     // 返回的永遠都是第一次 new Person 的例項      // 也就是永遠都是一個例項      return   instance} const   p1   =   singleton() const   p2   =   singleton()console.log(p1   ===   p2)   // true

應用

·  我們就用這個核心程式碼簡單書寫一個 demo

// 這個建構函式的功能就是建立一個 div,新增到頁面中 function   CreateDiv()   {

     this .div   =   document .createElement( 'div' )

     document .body.appendChild( this .div)} CreateDiv.prototype.init   =   function   (text)   {

     this .div.innerHTML   =   text} // 準備把這個 CreateDiv 做成單例模式// 讓 singleton 成為一個閉包函式 const   singleton   =   ( function   ()   {

     let   instance

     return   function   (text)   {

         if   ( ! instance)   {

             instance   =   new   CreateDiv()

         }

         instance.init(text)

         return   instance

     }})() singleton( 'hello' )   // 第一次的時候,頁面中會出現一個新的 div ,內容是 hello singleton( 'world' )   // 第二次的時候,不會出現新的 div,而是原先的 div 內容變成了 world

組合模式

·  組合模式,就是把幾個建構函式的啟動方式組合再一起

·  然後用一個 ”遙控器“ 進行統一呼叫

class   GetHome   {

     init   ()   {

         console.log( '到家了' )

     }} class   OpenComputer   {

     init   ()   {

         console.log( '開啟電腦' )

     }} class   PlayGame   {

     init   ()   {

         console.log( '玩遊戲' )

     }}

·  上面幾個建構函式的創造的例項化物件的  啟動方式  都一致

·  那麼我們就可以把這幾個函式以組合模式的情況書寫

·  然後統一啟動

·  準備一個  組合模式  的建構函式

class   Compose   {

     constructor   ()   {

         this .compose   =   []

     }

     // 新增任務的方法      add   (task)   {

         this .compose.push(task)

     }

     // 一個執行任務的方法      execute   ()   {

         this .compose.forEach(item   =>   {

             item.init()

         })

     }}

·  我們就用我們的組合模式建構函式來吧前面的幾個功能組合起來

const   c   =   new   Compose() // 把所有要完成的任務都放在佇列裡面 c.add( new   GetHome())c.add( new   OpenComputer)c.add( new   PlayGame) // 直接器動任務佇列 c.execute() // 就會按照順序執行三個物件中的 init 函式

觀察者模式

·  觀察者模式,通常也被叫做  釋出-訂閱模式  或者  訊息模式

·  英文名稱叫做  Observer

·  官方解釋: 當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新,解決了主體物件與觀察者之間功能的耦合,即一個物件狀態改變給其他物件通知的問題

·  聽起來很迷糊,但是其實沒有很難

一個例子

·  當你想去書店買書,但是恰巧今天你要買的書沒有了

·  我們又不能總在書店等著,就把我們的手機留給店員

·  當你需要的書到了的時候,他會打電話通知你,你去買了就好了

·  你買到數了以後,就告訴他,我買到了,那麼以後再來了書就不會通知你了

addEventListener

·  上面的例子可能還不是很明確

·  但是  addEventListener  是一個我們都用過的東西

·  這個東西其實就是一個標準的  觀察者模式

btn.addEventListener( 'click' ,   function   ()   {

     console.log( 'btn 被點選了' )})

·  上面這個就是有一個  無形的觀察者  再觀察著  btn  的一舉一動

·  當這個  btn  被點選的時候,就會執行 對應的函式

·  我們也可以多繫結幾個函式

·  說白了: 觀察者模式就是我們自己實現一個  addEventListener  的功能

·  只不過  addEventListaner  只有固定的一些事件,而且只能給 dom 元素繫結

·  而我們自己寫的可以隨便繫結一個事件名稱,自己選擇觸發時機而已

書寫程式碼

·  首先我們分析功能

·  我們要有一個觀察者(這裡抽象為一個物件  {}

·  需要有一個屬性,存放訊息的盒子(把你繫結的所有事件放在裡面)

·  需要一個 on 方法,用於新增事件

·  需要一個 emit 方法,用於釋出事件(觸發)

·  需要一個 off 方法,把已經新增的方法取消

const   observer   =   {

     message :   {},

     on :   function   ()   {},

     emit :   function   ()   {},

     off :   function   ()   {}}

·  我們把它寫成一個建構函式的形式

class   Observer   {

     constructor   ()   {

         this .message   =   {}

     }

     on   ()   {}

     emit   ()   {}

     off   ()   {}}

·  現在,一個觀察者的雛形就出來了

·  接下來完善方法就可以了

ON

·  先來寫 ON 方法

·  新增一個事件

·  我們的 on 方法需要接受 兩個引數

·  事件型別

·  事件處理函式

class   Observer   {

     constructor   ()   {

         this .message   =   {}

     }

     on(type,   fn)   {

         // 判斷訊息盒子裡面有沒有設定事件型別          if   ( !this .message[type])   {

             // 證明訊息盒子裡面沒有這個事件型別              // 那麼我們直接新增進去              // 並且讓他的值是一個陣列,再陣列裡面放上事件處理函式              this .message[type]   =   [fn]

         }   else   {

             // 證明訊息盒子裡面有這個事件型別              // 那麼我們直接向陣列裡面追加事件處理函式就行了              this .message[type].push(fn)

         }

     }

     emit   ()   {}

     off   ()   {}}

EMIT

·  接下來就是釋出事件

·  也就是讓我們已經訂閱好的事件執行一下

·  同樣需要接受兩個引數

·  要觸發的事件型別

·  給事件處理函式傳遞的引數

class   Observer   {

     constructor   ()   {

         this .message   =   {}

     }

     on(type,   fn)   {

         // 判斷訊息盒子裡面有沒有設定事件型別          if   ( !this .message[type])   {

             // 證明訊息盒子裡面沒有這個事件型別              // 那麼我們直接新增進去              // 並且讓他的值是一個陣列,再陣列裡面放上事件處理函式              this .message[type]   =   [fn]

         }   else   {

             // 證明訊息盒子裡面有這個事件型別              // 那麼我們直接向陣列裡面追加事件處理函式就行了              this .message[type].push(fn)

         }

     }

     emit(type,   ...arg)   {

         // 判斷你之前有沒有訂閱過這個事件          if   ( !this .message[type])   return

         // 如果有,那麼我們就處理一下引數          const   event   =   {

             type :   type,

             arg :   arg   ||   {}

         }

         // 迴圈執行為當前事件型別訂閱的所有事件處理函式          this .message[type].forEach(item   =>   {

             item.call( this ,   event)

         })

     }

     off()   {}}

OFF

·  最後就是移除事件

·  就是把已經訂閱的事件處理函式移除掉

·  同樣需要接受兩個引數

·  要移除的事件型別

·  要移除的事件處理函式

class   Observer   {

     constructor   ()   {

         this .message   =   {}

     }

     on(type,   fn)   {

         // 判斷訊息盒子裡面有沒有設定事件型別          if   ( !this .message[type])   {

             // 證明訊息盒子裡面沒有這個事件型別              // 那麼我們直接新增進去              // 並且讓他的值是一個陣列,再陣列裡面放上事件處理函式              this .message[type]   =   [fn]

         }   else   {

             // 證明訊息盒子裡面有這個事件型別              // 那麼我們直接向陣列裡面追加事件處理函式就行了              this .message[type].push(fn)

         }

     }

     emit(type,   ...arg)   {

         // 判斷你之前有沒有訂閱過這個事件          if   ( !this .message[type])   return

         // 如果有,那麼我們就處理一下引數          const   event   =   {

             type :   type,

             arg :   arg   ||   {}

         }

         // 迴圈執行為當前事件型別訂閱的所有事件處理函式          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() // 準備兩個事件處理函式 function   a(e)   {

     console.log( 'hello' )} function   b(e)   {

     console.log( 'world' )} // 訂閱事件 o.on( 'abc' ,   a)o.on( 'abc' ,   b) // 釋出事件(觸發) o.emit( 'abc' ,   '100' ,   '200' ,   '300' )   // 兩個函式都回執行 // 移除事件 o.off( 'abc' ,   'b' ) // 再次釋出事件(觸發) o.emit( 'abc' ,   '100' ,   '200' ,   '300' )   // 只執行一個 a 函式了

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2701905/,如需轉載,請註明出處,否則將追究法律責任。

相關文章