站長資訊網
        最全最豐富的資訊網站

        JavaScript經典講解之設計模式(實例詳解)

        本篇文章給大家帶來了關于JavaScript中設計模式的相關知識,其中包括單例模式、組合模式、觀察者模式等等,希望對大家有幫助。

        JavaScript經典講解之設計模式(實例詳解)

        1 設計模式

        概念

        設計模式是為了解決某種問題,而設計的一套最佳解決方案。
        面向對象 – 更加注重對象 – 找一種最佳的定義對象并個對象添加屬性和方法 的 方案
        找到的最佳的解決方案 – 就是一種設計模式

        針對不同的問題,我們會有不同的最佳解決方案 – 設計模式

        常見的設計模式:

        • 單例模式
        • 組合模式
        • 觀察者模式
        • 命令模式
        • 代理模式
        • 工廠模式
        • 策略模式
        • 適配器模式
        • 。。。

        1.1 單例模式

        數據庫連接 – 多個功能都需要操作數據庫 – 重新連接數據庫 – 1000個功能,連接1000次數據庫

        注冊功能,每次注冊都需要操作數據庫 – 同一時間有1000個人在注冊

        mysql數據庫有一個連接限制:最多只能支持同時又200個連接

        我們連接一次數據庫,得到一個連接,多次操作數據庫,使用這一個連接其就能操作

        怎么操作,讓多次執行數據庫語句使用同一個連接 – 我們就可以設計一個設計模式

        設計模式:定義一個類,這個類new以后就得到一個連接,以后每次執行數據庫語句的時候,都可以從這個類中得到一個連接
        單例模式:從一個類中只能得到一個對象 – 不管操作了多少次這個類,最終得出的所有連接對象都是同一個對象

        讓一個類創建出來的所有對象,里面的所有屬性和方法都一模一樣。比如封裝一個類,將一些常用的操作函數作為方法放進去,以后每次都使用同一個對象來調用這些方法

        正常情況,一個類創建出來的每個對象都是不一樣的。

        class Carousel{     }var a = new Carousel();var b = new Carousel();console.log(a === b); // false

        單例模式就是讓這兩個對象是一樣的,也就是說,一個類永遠只有一個實例對象

        var single = (function(){     class Carousel{             }     var res = undefined;     return function(){         if(!res){            res = new Carousel();         }         return res;     }})();var s1 = single();var s2 = single();console.log(s1 === s2); // true

        變量P暴露在全局的變量會造成全局的污染
        利用閉包解決每次都會重新定義p的問題

        單例模式的核心代碼:

        function Person(){}function fn(Person){     var p;     return function(){         if(!p){             p = new Person;         }         return p;     }}var f = fn(Person)var p1 = f()var p2 = f()

        單例模式的應用場景在封裝工具庫。

        例:封裝封裝一個工具庫
        單例模式 應用 封裝工具庫

             工具庫中會有很多的方法 - 方法每次的使用 應該是同一個對象使用的,而不是應該每次都有一個新對象在使用工具
               // var t = new Tool;         // t.setCookie('username', 'zs', 20);         const Tool = (function () {             class Tool {                 constructor() {                     if (window.getComputedStyle) {                         this.flag = true;                     } else {                         this.flag = false;                     }                 }                 /獲取節點屬性                getStyle(ele, attr) {                     if (this.flag) {                         return window.getComputedStyle(ele)[attr];                     } else {                         return ele.currentStyle[attr];                     }                 }                  getStyle(ele, attr) {                      嘗試一段代碼   不知道會不會報錯                      嘗試成功 后面代碼沒有什么事                     嘗試失敗 會報錯 被cathch 捕獲到  會將錯誤信息放到err參數里  catch{} 里可以處理這個錯誤 也可以不處理這個錯誤對上面的錯誤代碼進行補救  錯誤不會再瀏覽器里報錯                    try {                         return window.getComputedStyle(ele)[attr];                     } catch (err) {                         return ele.currentStyle[attr];                     }                 }                 // 設置節點css屬性                 setStyle(ele, styleObj) {                     for (let attr in styleObj) {                          ele.style[attr] = styleObj[attr];                     }                 }                 // 設置cookie                 setCookie(key, value, second, path = '/') {                     let data = new Date();                     date.setTime(date.getTime() - 8 * 3600 * 1000 + second * 1000);                     document.cookie = `${key}=${value};expires=${date};path=${path}`;                 }             }             var tool;             return (function () {                 if (!tool) {                     tool = new Tool();                 }                 return tool;             })();         })();

        1.3 組合模式

        組合模式就是制作啟動器。多個類在實例化以后,執行起來使用一個同名的方法來啟動,這時候可以做一個啟動器,讓多個類一起啟動。

        class Carousel{     init(){         console.log("輪播圖開始運行");     }}class Tab{     init(){         console.log("選項卡開始運行");     }}class Enlarge{     init(){ 		console.log("放大鏡開始運行");     }}// 這3個類要運行起來需要各自實例化,并調用每個類中的init方法,此時就可以使用組合模式做一個啟動器

        組合模式制作啟動器:

        class Starter{     constructor(){ 		this.arr = []; // 定義一個數組     }     add(className){         this.arr.push(className); // 將這個多個類放進數組     }     run(){         for(var i=0;i<this.arr.length;i++){             arr[i].init(); // 讓數組中的每個類都調用init方法         }     }}var starts = new Starter();starts.add(new Carousel);starts.add(new Tab);starts.add(new Enlarge);starts.run();

        1.4 發布訂閱模式

        https://blog.csdn.net/weixin_44070254/article/details/117574565?spm=1001.2014.3001.5501

        有人訂閱 有人發布
        發布訂閱模式:需要一個觀察者 需要一個被觀察者 如果觀察者發現被觀察者的狀態發生了改變,就需要執行一個任務
        定義一個觀察者:

        class Observer{     // 觀察者有名字和任務     constructor(name,task){         this.name = name        this.task = task    }}// 定義班主任var bzr = new Observer('班主任',function(state){     console.log("因為"+state+",所以"+this.name+"罰站");})// 定義了一個年級主任var zr = new Observer('年級主任',function(state){     console.log("因為"+state+",所以"+this.name+"要找班主任");})// 被觀察者class Subject{     // 有自己的狀態     constructor(state){         this.state = state        // 觀察者們         this.observer = [];     }     // 添加被觀察者     add(...arr){         this.observer = this.observer.concat(arr)     }     // 改變狀態     changeSate(state){         this.state = state        // 觸發觀察者的任務         for(let i=0;i<this.observer.length;i++){             this.observer[i].task(state)         }     }}var xm = new Subject('學習')xm.add(bzr,zr)// xm.changeSate('摸了一下小紅的手')xm.changeSate('玩游戲')

        觀察者模式,又稱發布-訂閱模式。意思是讓一個人不停的監控某件某件東西,當這個東西要發生某種行為的時候,這個人就通知一個函數執行這個行為的操作。

        例:當事件的代碼寫好以后,其實這個事件就不停的監控用戶在頁面中的行為,一旦用戶觸發這個事件的時候,就調用函數處理這個事件。

        p.addEventListener("click",function(){}); // 這個事件寫好以后,就一直在頁面中監控用戶行為,用戶點擊這個元素的時候,就調用函數

        觀察者模式就是類似的操作,寫觀察者模式的目的,是為了給一個非元素的數據綁定一個自定義事件。

        例:給一個obj綁定一個abc的事件

        分析:

        給一個元素綁定事件,有綁定方法,有觸發條件,有取消綁定。

        要給一個對象綁定一個自定義事件。那么這個事件如何綁定,如何觸發,如何解綁這個事件。

        所以:

        • 需要一個方法處理事件的綁定。
        • 需要一個方法處理如何觸發這個事件。
        • 需要一個方法處理如何解綁這個事件。

        元素的事件,一個事件類型可以綁定多個處理函數。

        對象的自定義事件如何讓一個事件類型綁定多個函數。

        所以:

        需要一個空間,存儲事件類型對應的處理函數們。

        1.4.1 雛形:

        class watch{     bind(){              }     touch(){              }     unbind(){              }}var w = new watch();

        此時,如要給這個對象綁定事件和處理函數的話,需要事件類型和處理函數作為參數,所以調用時要傳入實參

        var w = new watch();w.bind("cl",a); // 給w對象綁定cl事件類型,執行a函數w.bind("cl",b); // 給w對象綁定cl事件類型,執行b函數function a(){     console.log("事件處理函數a");}function b(){     console.log("事件處理函數b");}

        1.4.2 綁定

        在bind方法中接收參數,并將事件類型和處理函數對應存儲起來:

        constructor(){     this.obj = {} // 存儲格式:{事件類型:[函數1,函數2]}}bind(type,handle){     this.obj[type] = [handle]; // 對象存儲方式{"cl":[a]}}

        如果給這個事件再綁定一個函數b的話,會將原來的a覆蓋掉,所以,應該先判斷,如果對應的這個數組中沒有數據就直接放進去,如果有了就應該追加

        bind(type,handle){     if(!this.obj[type]){         this.obj[type] = [handle]; // 對象存儲方式{"cl":[a]}     }else{         this.obj[type].push(handle);     }  }

        打印w對象的結果:

        綁定后的存儲結果
        JavaScript經典講解之設計模式(實例詳解)

        1.4.3 觸發

        觸發這個事件需要傳入觸發哪個事件類型

        touch(type){     // 首先要判斷,這個事件類型是否綁定,沒有綁定不能觸發     if(!this.obj[type]){         return false;     }else{         // 將這個事件的所有綁定的處理函數一起調用         for(var i=0;i<this.obj[type].length;i++){             this.obj[type][i]();         }     }}

        測試:

        觸發測試
        JavaScript經典講解之設計模式(實例詳解)

        這兩個處理函數都沒有參數,如果要傳入參數的時候該怎么處理?

        觸發事件的時候就要傳入實參

        w.touch("cl","張三",20);

        觸發事件的方法就應該處理這些參數

        touch(type,...arr){ // 因為參數不定長,所以使用合并運算符     // 首先要判斷,這個事件類型是否綁定,沒有綁定不能觸發     if(!this.obj[type]){         return false;     }else{         // 處理參數:模擬系統事件的參數事件對象,將所有參數都集中在一個對象中         var e = {             type:type,             args:arr        }         // 將這個事件的所有綁定的處理函數一起調用         for(var i=0;i<this.obj[type].length;i++){             this.obj[type][i](e);         }     }}

        添加一個帶參數的處理函數,并觸發事件執行:

        w.bind("cl",c); // 給w對象綁定cl事件類型,執行c函數w.touch("cl","張三",20);function c(e){     console.log("我是處理函數c,打?。盒彰?quot;+e.name+",年齡"+e.age);}

        結果:

        帶參數的處理函數處理結果
        JavaScript經典講解之設計模式(實例詳解)

        1.4.5 解綁

        解綁也需要知道解綁的事件類型和處理函數

        unbind(type,handle){     // 先判斷是否綁定了這個事件     if(!this.obj[type]){         return false;     }else{         // 從數組中將這個處理函數刪除         for(var i=0;i<this.obj[type].length;i++){             if(this.obj[type][i] === type){                 this.obj[type].splice(i,1);                 i--; // 放置數組塌陷             }         }     }}

        解綁測試:

        解綁測試結果
        JavaScript經典講解之設計模式(實例詳解)

        如果綁定事件的時候使用的匿名函數,就無法進行解綁了,所以再添加一個解綁事件所有處理函數的方法:

        clear(type){     if(!this.obj[type]){         return false;     }else{         // 直接從對象中將這個屬性刪除         delete this.obj[type];     } }

        1.5 觀察者模式

        觀察者模式跟發布訂閱模式不一樣的地方在于,要有觀察者和被觀察者。

        創建觀察者:

        // 創建觀察者class Observer{     // 觀察者有姓名和技能 - 技能是一個函數     constructor(name,skill){         this.name = name;         this.skill = skill    }}// 創建觀察者var bzr = new Observer('班主任',function(state){     console.log('因為'+state+'叫家長')})var xz = new Observer('校長',function(state){     console.log('因為'+state+'叫班主任')})console.log(bzr,xz)

        JavaScript經典講解之設計模式(實例詳解)

        創建被觀察者:

        // 創建被觀察者     class Subject{         // 被觀察者有狀態 和 觀察者列表         constructor(state){             this.state = state            this.observers = []         }         // 添加觀察者         addObserver(observer){             var index = this.observers.findIndex(v=>v === observer)             if(index<0){                 this.observers.push(observer)             }         }         // 改變狀態         setState(val){             if(val!==this.state){                 this.state = val;                 this.observers.forEach(v=>{                     v.skill(this.state)                 })             }         }         // 刪除觀察者         delObserver(observer){             var index = this.observers.findIndex(v=>v === observer)             if(index>=0){                 this.observers.splice(index,1)             }         }     }     // 創建被觀察者     var xm = new Subject('學習')     // 添加觀察者     xm.addObserver(bzr)     xm.addObserver(xz)     xm.addObserver(bzr)     console.log(xm)     // 改變狀態     xm.setState('玩游戲')

        JavaScript經典講解之設計模式(實例詳解)


        1.6 策略模式

        一個問題有多種解決方案,且隨時還可以有

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 69国产成人综合久久精品| 国产精品成人观看视频免费| 精品欧洲AV无码一区二区男男 | 精品久久一区二区三区| 麻豆国产高清精品国在线| 91精品国产福利在线观看| 成人精品在线视频| 精品久久久久久亚洲精品| 亚洲国产精品第一区二区三区| 91亚洲精品自在在线观看| 岛国精品一区免费视频在线观看| 亚洲AV无码久久精品色欲| 亚洲精品无码av天堂| 欧美激情精品久久久久久久九九九 | 99久久久国产精品免费无卡顿| 熟女精品视频一区二区三区| 欧美激情精品久久久久久| 国产一区二区精品久久岳| 色播精品免费小视频| 国产精品1024香蕉在线观看 | 久久精品蜜芽亚洲国产AV| 午夜精品久久久内射近拍高清| 精品欧美一区二区在线观看| 色偷偷888欧美精品久久久| 国产成人精品免费视频网页大全 | 欧美精品黑人巨大在线播放| 99re8这里有精品热视频免费| 国产精品久久久久国产A级| 久久久精品国产sm调教网站| 尤物yw午夜国产精品视频| 中文字幕精品亚洲无线码二区| 中文字幕日本精品一区二区三区| 在线亚洲精品福利网址导航| 亚洲精品国产美女久久久| 亚洲精品无码精品mV在线观看| 亚洲国产美女精品久久久久∴| 亚洲午夜福利精品久久| 少妇人妻偷人精品无码视频新浪| 久久香综合精品久久伊人| 精品久久久久久无码专区不卡| 国产精品第12页|