溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript的設計模式怎么實現(xiàn)

發(fā)布時間:2022-02-09 09:34:49 來源:億速云 閱讀:124 作者:iii 欄目:web開發(fā)

這篇文章主要講解了“JavaScript的設計模式怎么實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript的設計模式怎么實現(xiàn)”吧!

JavaScript的設計模式怎么實現(xiàn)

1 設計模式

概念

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

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

常見的設計模式:

  • 單例模式

  • 組合模式

  • 觀察者模式

  • 命令模式

  • 代理模式

  • 工廠模式

  • 策略模式

  • 適配器模式

  • 。。。


1.1 單例模式

數(shù)據(jù)庫連接 - 多個功能都需要操作數(shù)據(jù)庫 - 重新連接數(shù)據(jù)庫 - 1000個功能,連接1000次數(shù)據(jù)庫

注冊功能,每次注冊都需要操作數(shù)據(jù)庫 - 同一時間有1000個人在注冊

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

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

怎么操作,讓多次執(zhí)行數(shù)據(jù)庫語句使用同一個連接 - 我們就可以設計一個設計模式

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

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

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

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;
                    }
                }
                /獲取節(jié)點屬性                getStyle(ele, attr) {
                    if (this.flag) {
                        return window.getComputedStyle(ele)[attr];
                    } else {
                        return ele.currentStyle[attr];
                    }
                }

                getStyle(ele, attr) {
                     嘗試一段代碼   不知道會不會報錯
                     嘗試成功 后面代碼沒有什么事
                    嘗試失敗 會報錯 被cathch 捕獲到  會將錯誤信息放到err參數(shù)里  catch{} 里可以處理這個錯誤 也可以不處理這個錯誤對上面的錯誤代碼進行補救  錯誤不會再瀏覽器里報錯                    try {
                        return window.getComputedStyle(ele)[attr];
                    } catch (err) {
                        return ele.currentStyle[attr];
                    }
                }
                // 設置節(jié)點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 組合模式

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

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

組合模式制作啟動器:

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

1.4 發(fā)布訂閱模式

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

有人訂閱 有人發(fā)布
發(fā)布訂閱模式:需要一個觀察者 需要一個被觀察者 如果觀察者發(fā)現(xiàn)被觀察者的狀態(tài)發(fā)生了改變,就需要執(zhí)行一個任務
定義一個觀察者:

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{
    // 有自己的狀態(tài)
    constructor(state){
        this.state = state        // 觀察者們
        this.observer = [];
    }
    // 添加被觀察者
    add(...arr){
        this.observer = this.observer.concat(arr)
    }
    // 改變狀態(tài)
    changeSate(state){
        this.state = state        // 觸發(fā)觀察者的任務
        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('玩游戲')

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

例:當事件的代碼寫好以后,其實這個事件就不停的監(jiān)控用戶在頁面中的行為,一旦用戶觸發(fā)這個事件的時候,就調(diào)用函數(shù)處理這個事件。

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

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

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

分析:

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

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

所以:

  • 需要一個方法處理事件的綁定。

  • 需要一個方法處理如何觸發(fā)這個事件。

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

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

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

所以:

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

1.4.1 雛形:
class watch{
    bind(){
        
    }
    touch(){
        
    }
    unbind(){
        
    }}var w = new watch();

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

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

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

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

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

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

打印w對象的結果:

綁定后的存儲結果
JavaScript的設計模式怎么實現(xiàn)

1.4.3 觸發(fā)

觸發(fā)這個事件需要傳入觸發(fā)哪個事件類型

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

測試:

觸發(fā)測試
JavaScript的設計模式怎么實現(xiàn)

這兩個處理函數(shù)都沒有參數(shù),如果要傳入?yún)?shù)的時候該怎么處理?

觸發(fā)事件的時候就要傳入實參

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

觸發(fā)事件的方法就應該處理這些參數(shù)

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

添加一個帶參數(shù)的處理函數(shù),并觸發(fā)事件執(zhí)行:

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

結果:

帶參數(shù)的處理函數(shù)處理結果
JavaScript的設計模式怎么實現(xiàn)

1.4.5 解綁

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

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

解綁測試:

解綁測試結果
JavaScript的設計模式怎么實現(xiàn)

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

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

1.5 觀察者模式

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

創(chuàng)建觀察者:

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

JavaScript的設計模式怎么實現(xiàn)

創(chuàng)建被觀察者:

// 創(chuàng)建被觀察者
    class Subject{
        // 被觀察者有狀態(tài) 和 觀察者列表
        constructor(state){
            this.state = state            this.observers = []
        }
        // 添加觀察者
        addObserver(observer){
            var index = this.observers.findIndex(v=>v === observer)
            if(index<0){
                this.observers.push(observer)
            }
        }
        // 改變狀態(tài)
        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)
            }
        }
    }
    // 創(chuàng)建被觀察者
    var xm = new Subject('學習')
    // 添加觀察者
    xm.addObserver(bzr)
    xm.addObserver(xz)
    xm.addObserver(bzr)
    console.log(xm)
    // 改變狀態(tài)
    xm.setState('玩游戲')

JavaScript的設計模式怎么實現(xiàn)


1.6 策略模式

一個問題有多種解決方案,且隨時還可以有更多的解決方案,就是策略模式。例如:一個商品在售賣的時候,會有多種折扣方式,慢100減10元,滿200減30元等…

商品活動:
滿100減10
滿200減30
滿300打8折

策略模式:將折扣放在閉包中保存起來 - 通過閉包對折扣進行增刪改查操作

正常的函數(shù)表達方式:

function fn(type,price){
    if(type === '100_10'){
       return price -= 10
    }else if(type === '200_30'){
       return price -= 0
    }else{
        return '沒有這種折扣'
    }}fn('100_10',160)

這種方式,在添加折扣或刪除折扣的時候總是需要修改原函數(shù)。

策略模式代碼:

var calcPrice = (function(){
    // 以閉包的形式存儲折扣數(shù)據(jù)
    var sale = {
        '100_10':function(price){
            return price -= 10
        },
        '200_20':function(price){
            return price -= 20
        }
    }
    function calcPrice(type,price){
        // 閉包中使用折扣
        if(type in sale){
            return sale[type](price)
        }else{
            return '沒有這個折扣'
        }
    }
    // 折扣函數(shù)添加屬性 - 添加折扣
    calcPrice.add = function(type,fn){
        if(type in sale){
            console.log('折扣存在')
        }else{
            sale[type] = fn        }
    }
    // 刪除折扣
    calcPrice.del = function(type){
        if(type in sale){
            delete sale[type]
        }else{
            console.log('折扣不存在')
        }
    }
    return calcPrice})()var p = calcPrice('100_10',200)calcPrice.add('200_320',function(price){
    return price -= 50})calcPrice.del('200_330')var p = calcPrice('200_320',200)console.log(p)

感謝各位的閱讀,以上就是“JavaScript的設計模式怎么實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對JavaScript的設計模式怎么實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI