1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        我理解的前端設(shè)計(jì)模式

        共 17224字,需瀏覽 35分鐘

         ·

        2021-05-09 03:23

        點(diǎn)擊上方 前端瓶子君,關(guān)注公眾號(hào)

        回復(fù)算法,加入前端編程面試算法每日一題群

        來(lái)源:hannie76327

        https://juejin.cn/post/6953872475537014820

        用自己通俗易懂的語(yǔ)言理解設(shè)計(jì)模式。

        通過(guò)對(duì)每種設(shè)計(jì)模式的學(xué)習(xí),更加加深了我對(duì)它的理解,也能在工作中考慮應(yīng)用場(chǎng)合。

        成文思路:分析每種設(shè)計(jì)模式思想、抽離出應(yīng)用場(chǎng)景、對(duì)這些模式進(jìn)行對(duì)比

        此篇文章包含:修飾者模式(裝飾器)、單例模式、工廠模式、訂閱者模式、觀察者模式、代理模式

        將不變的部分和變化的部分隔開(kāi)是每個(gè)設(shè)計(jì)模式的主題。

        單例模式

        也叫單體模式,核心思想是確保一個(gè)類只對(duì)應(yīng)一個(gè)實(shí)例。

        特點(diǎn):

        • 只允許一個(gè)例存在,提供全局訪問(wèn)點(diǎn),緩存初次創(chuàng)建的變量對(duì)象

        • 排除全局變量,防止全局變量被重寫(xiě)

        • 可全局訪問(wèn)

          // 工廠模式和new模式實(shí)現(xiàn)單例模式

          vue的安裝插件屬于單例模式

          適用場(chǎng)景:適用于彈框的實(shí)現(xiàn), 全局緩存,一個(gè)單一對(duì)象。比如:彈窗,無(wú)論點(diǎn)擊多少次,彈窗只應(yīng)該被創(chuàng)建一次。

          缺點(diǎn):

        防止全局變量被污染,看過(guò)多種寫(xiě)法,總結(jié)在一起,更能融會(huì)貫通

        直接使用字面量(全局對(duì)象)

        const person = {
          name'哈哈',
          age18
        }

        了解 const 語(yǔ)法的小伙伴都知道,這只喵是不能被重新賦值的,但是它里面的屬性其實(shí)是可變的。

        如果想要一個(gè)不可變的單例對(duì)象:

        const person = {
          name'哈哈',
          age18
        }
        Object.freeze(person);

        這樣就不能新增或修改person的任何屬性.

        如果是在模塊中使用,上面的寫(xiě)法并不會(huì)污染全局作用域,但是直接生成一個(gè)固定的對(duì)象缺少了一些靈活性

        使用構(gòu)造函數(shù)的靜態(tài)屬性

        class寫(xiě)法

        class A {
          constructor () {
            if (!A._singleton) {
              A._singleton = this;
            }
            return A._singleton;
          }
          log (...args) {
            console.log(...args);
          }
        }
        var a1 = new A() 
        var a2= new A()
        console.log(a1 === a2)//true

        構(gòu)造函數(shù)寫(xiě)法

        function A(name){
            // 如果已存在對(duì)應(yīng)的實(shí)例
           if(typeof A._singleton === 'object'){
               return A._singleton
           }
           //否則正常創(chuàng)建實(shí)例
           this.name = name
           
           // 緩存
           A._singleton =this
           return this
        }
        var a1 = new A() 
        var a2= new A()
        console.log(a1 === a2)//true

        缺點(diǎn):在于靜態(tài)屬性是能夠被人為重寫(xiě)的,不過(guò)不會(huì)像全局變量那樣被無(wú)意修改。

        借助閉包

        1. 考慮重寫(xiě)構(gòu)造函數(shù):當(dāng)對(duì)象第一次被創(chuàng)建以后,重寫(xiě)構(gòu)造函數(shù),在重寫(xiě)后的構(gòu)造函數(shù)里面訪問(wèn)私有變量。
        function A(name){
          var instance = this
          this.name = name
          //重寫(xiě)構(gòu)造函數(shù)
          A = function (){
              return instance
          }
            //重寫(xiě)構(gòu)造函數(shù)之后,實(shí)際上原先的A指針對(duì)應(yīng)的函數(shù)實(shí)際上還在內(nèi)存中(因?yàn)閕nstance變量還在被引用著),但是此時(shí)A指針已經(jīng)指向了一個(gè)新的函數(shù)了
        }
        A.prototype.pro1 = "from protptype1"

        var a1 = new A() 
        A.prototype.pro2 = "from protptype2"
        var a2= new A()

        console.log(a1.pro1)//from protptype1
        console.log(a1.pro2)//underfined
        console.log(a2.pro1)//from protptype1
        console.log(a2.pro2)//underfined
        console.log(a1.constructor ==== A)  //false

        為了解決A指針指向新地址的問(wèn)題,實(shí)現(xiàn)原型鏈繼承

        function A(name){
          var instance = this
          this.name = name
         
          //重寫(xiě)構(gòu)造函數(shù)
          A = function (){
              return instance
          }
          
          // 第一種寫(xiě)法,這里實(shí)際上實(shí)現(xiàn)了一次原型鏈繼承,如果不想這樣實(shí)現(xiàn),也可以直接指向舊的原型
          A.prototype = this
          // 第二種寫(xiě)法,直接指向舊的原型
          A.prototype = this.constructor.prototype
          
          instance = new A()
          
          // 調(diào)整構(gòu)造函數(shù)指針,這里實(shí)際上實(shí)現(xiàn)了一次原型鏈繼承,如果不想這樣實(shí)現(xiàn),也可以直接指向原來(lái)的原型
          instance.constructor = A
         
          return instance
        }
        A.prototype.pro1 = "from protptype1"

        var a1 = new A() 
        A.prototype.pro2 = "from protptype2"
        var a2= new A()

        console.log(a1.pro1)//from protptype1
        console.log(a1.pro2)//from protptype2
        console.log(a2.pro1)//from protptype1
        console.log(a2.pro2)//from protptype2
        1. 利用立即執(zhí)行函數(shù)來(lái)保持私有變量
        var A;
        (function(name){
            var instance;
            A = function(name){
                if(instance){
                    return instance
                }
                
                //賦值給私有變量
                instance = this
                
                //自身屬性
                this.name = name
            }
        }());
        A.prototype.pro1 = "from protptype1"

        var a1 = new A('a1'
        A.prototype.pro2 = "from protptype2"
        var a2 = new A('a2')

        console.log(a1.name)
        console.log(a1.pro1)//from protptype1
        console.log(a1.pro2)//from protptype2
        console.log(a2.pro1)//from protptype1
        console.log(a2.pro2)//from protptype2

        以上通過(guò)閉包的方式可以實(shí)現(xiàn)單例

        代理實(shí)現(xiàn)單例模式

         function singleton(name){
            this.name = name
          }
          let proxySingleton = function(){
            let instance = null
            return function(name){
              if(!instance){
                instance = new singleton(name)
              }
              return instance
            }
          }()
          let a1= new proxySingleton('a1')
          let a2= new proxySingleton('a2')

         console.log(123, a1===a2)

        工廠單例

        let logger = null
        class Logger {
          log (...args) {
            console.log(...args);
          }
        }
        function createLogger({
          if (!logger) {
            logger = new Logger();
          }
          return logger;
        }
        let a = new createLogger().log('12')
        let b = new createLogger().log('121')
        console.log(new createLogger(), a===b)

        根據(jù)理解,我自己喜歡用代理方式實(shí)現(xiàn),更好理解。如果總結(jié)有錯(cuò),歡迎指正。

        參考:?jiǎn)卫J?/p>

        工廠模式

        不暴露創(chuàng)建對(duì)象的邏輯,封裝在一個(gè)函數(shù)中。工廠模式根據(jù)抽象程度的不同可以分為:簡(jiǎn)單工廠,工廠方法和抽象工廠。

        簡(jiǎn)單工廠模式

        簡(jiǎn)單工廠模式又叫靜態(tài)工廠模式,由一個(gè)工廠對(duì)象決定創(chuàng)建某一種產(chǎn)品對(duì)象類的實(shí)例。主要用來(lái)創(chuàng)建同一類對(duì)象。

        簡(jiǎn)單工廠的優(yōu)點(diǎn)在于,你只需要一個(gè)正確的參數(shù),就可以獲取到你所需要的對(duì)象,而無(wú)需知道其創(chuàng)建的具體細(xì)節(jié)

        但是在函數(shù)內(nèi)包含了所有對(duì)象的創(chuàng)建邏輯(構(gòu)造函數(shù))和判斷邏輯的代碼,每增加新的構(gòu)造函數(shù)還需要修改判斷邏輯代碼。當(dāng)我們的對(duì)象不是上面的3個(gè)而是30個(gè)或更多時(shí),這個(gè)函數(shù)會(huì)成為一個(gè)龐大的超級(jí)函數(shù),便得難以維護(hù)。所以,簡(jiǎn)單工廠只能作用于創(chuàng)建的對(duì)象數(shù)量較少,對(duì)象的創(chuàng)建邏輯不復(fù)雜時(shí)使用。

        工廠方法模式

        工廠方法模式的本意是將實(shí)際創(chuàng)建對(duì)象的工作推遲到子類中,這樣核心類就變成了抽象類。

        在工廠方法模式中,工廠父類負(fù)責(zé)定義創(chuàng)建產(chǎn)品對(duì)象的公共接口,而工廠子類則負(fù)責(zé)生成具體的產(chǎn)品對(duì)象, 這樣做的目的是將產(chǎn)品類的實(shí)例化操作延遲到工廠子類中完成,即通過(guò)工廠子類來(lái)確定究竟應(yīng)該實(shí)例化哪一個(gè)具體產(chǎn)品類。

        抽象工廠模式

        抽象工廠其實(shí)是實(shí)現(xiàn)子類繼承父類的方法。

        抽象工廠模式(Abstract Factory Pattern),提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)須指定它們具體的類。

        抽象工廠可以提供多個(gè)產(chǎn)品對(duì)象,而不是單一的產(chǎn)品對(duì)象。

        參考 :JavaScript設(shè)計(jì)模式與實(shí)踐--工廠模式

        觀察者模式或發(fā)布訂閱模式

        通常又被稱為 發(fā)布-訂閱者模式 或 消息機(jī)制,它**定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系**,只要當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新,解決了主體對(duì)象與觀察者之間功能的耦合,即一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問(wèn)題。

        最好理解的舉例:公司里發(fā)布通知,讓員工都知道。

        工作中碰到以下幾種,并進(jìn)行分析。

        用雙向綁定來(lái)分析此模式:

        雙向綁定維護(hù)4個(gè)模塊:observer監(jiān)聽(tīng)者、dep訂閱器、watcher訂閱者、compile編譯者

        訂閱器是手機(jī)訂閱者(依賴),如果屬性發(fā)生變化observer通知dep,dep通知watcher調(diào)用update函數(shù)(watcher類中有update函數(shù),并且將自己加入dep)去更新數(shù)據(jù),這是符合一對(duì)多的思想,也就是observer是一,watcher是多。compile解析指令,訂閱數(shù)據(jù)變化,綁定更新函數(shù)。

        理解下來(lái),compile類似于綁定員工的角色,把watcher加入一個(gè)集體,observer通知它們執(zhí)行。

        用子組件與父組件通信分析此模式:

        通過(guò) emit來(lái)發(fā)布消息,對(duì)訂閱者emit 來(lái)發(fā)布消息,對(duì)訂閱者 emit來(lái)發(fā)布消息,對(duì)訂閱者on 做統(tǒng)一處理。

        emit是發(fā)布訂閱者,emit是發(fā)布訂閱者,emit是發(fā)布訂閱者,on 是監(jiān)聽(tīng)執(zhí)行

        用DOM的事件綁定(比如click)分析此模式:

        addEventListener('click',()=>{})監(jiān)聽(tīng)click事件,當(dāng)點(diǎn)擊DOM就是向訂閱者發(fā)布這個(gè)消息。

        點(diǎn)擊DOM是發(fā)布,addEventListener是監(jiān)聽(tīng)執(zhí)行

        小結(jié)

        通過(guò)分析平時(shí)碰到的這種模式,更好的理解一和多分別對(duì)應(yīng)什么,也增加記憶。

        一(發(fā)布事件):通知、廣播發(fā)布

        多(訂閱事件,可能會(huì)做出不同的回應(yīng)):觀察者、監(jiān)聽(tīng)者、訂閱者

        發(fā)布和訂閱的意思都是變成多的角度(添加)

        一是對(duì)應(yīng)執(zhí)行,多是收集

        平時(shí)碰到的函數(shù)理解,寫(xiě)自己的函數(shù)也可以這么定義,有個(gè)全局Events=[]:

        publish/emit/點(diǎn)擊/notify 訂閱事件 調(diào)用函數(shù) subscribe/on/addEventListener 監(jiān)聽(tīng) push函數(shù)
        unsubscribe/off/removeEventListener 刪除

        其實(shí)分析以上幾種情況,發(fā)布訂閱模式和觀察者模式的思想差不多相同,但是也是有區(qū)別:

        • 觀察者模式中需要觀察者對(duì)象自己定義事件發(fā)生時(shí)的相應(yīng)方法。
        • 發(fā)布訂閱模式者在發(fā)布對(duì)象和訂閱對(duì)象之中加了一個(gè)中介對(duì)象。我們不需要在乎發(fā)布者對(duì)象和訂閱者對(duì)象的內(nèi)部是什么,具體響應(yīng)時(shí)間細(xì)節(jié)全部由中介對(duì)象實(shí)現(xiàn)。
        訂閱的東西用Map或者Object類型來(lái)存儲(chǔ)。

        發(fā)布訂閱模式,有個(gè)中介,也可以說(shuō)是channel,但發(fā)現(xiàn)代碼實(shí)現(xiàn)差不多,只不過(guò)發(fā)布訂閱用來(lái)寫(xiě)包含有回調(diào)函數(shù)

        實(shí)例參考:JavaScript 設(shè)計(jì)模式之觀察者模式與發(fā)布訂閱模式

        juejin.cn/post/684490…

        juejin.cn/post/684490…

        裝飾者模式

        裝飾者模式的定義:在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)地添加方法。

        裝飾者模式的適用場(chǎng)合:

        • 如果你需要為類增添特性或職責(zé),可是從類派生子類的解決方法并不太現(xiàn)實(shí)的情況下,就應(yīng)該使用裝飾者模式。
        • 如果想為對(duì)象增添特性又不想改變使用該對(duì)象的代碼的話,則可以采用裝飾者模式。
        • 原有方法維持不變,在原有方法上再掛載其他方法來(lái)滿足現(xiàn)有需求;函數(shù)的解耦,將函數(shù)拆分成多個(gè)可復(fù)用的函數(shù),再將拆分出來(lái)的函數(shù)掛載到某個(gè)函數(shù)上,實(shí)現(xiàn)相同的效果但增強(qiáng)了復(fù)用性。

        裝飾者模式除了可以應(yīng)用在類上之外,還可以應(yīng)用在函數(shù)上(其實(shí)這就是高階函數(shù))

        我覺(jué)得可以是函數(shù)封裝原函數(shù)。這樣不改變?cè)瓉?lái)

        舉例:為汽車添加反光燈、后視鏡等這些配件

        碰到的:對(duì)函數(shù)進(jìn)行增強(qiáng)(節(jié)流函數(shù)or防抖函數(shù)、緩存函數(shù)返回值、構(gòu)造React高階組件,為組件增加額外的功能)

        參考:使用裝飾者模式做有趣的事情

        代理模式

        所謂的的代理模式就是為一個(gè)對(duì)象找一個(gè)替代對(duì)象,以便對(duì)原對(duì)象進(jìn)行訪問(wèn)。

        使用代理的原因是我們不愿意或者不想對(duì)原對(duì)象進(jìn)行直接操作,我們使用代理就是讓它幫原對(duì)象進(jìn)行一系列的操作,等這些東西做完后告訴原對(duì)象就行了。就像我們生活的那些明星的助理經(jīng)紀(jì)人一樣。

        原則:?jiǎn)我辉瓌t

        常用的虛代理形式:保護(hù)代理、緩存代理、虛擬代理。

        保護(hù)代理:明星委托助理或者經(jīng)紀(jì)人所要干的事;

        緩存代理:緩存代理就是將代理加緩存,更方便單一原則;

        常用的虛擬代理:某一個(gè)花銷很大的操作,可以通過(guò)虛擬代理的方式延遲到這種需要它的時(shí)候才去創(chuàng)建(例:使用虛擬代理實(shí)現(xiàn)圖片懶加載);

        先占位,加載完,再加載所需圖片
        var imgFunc = (function({
            var imgNode = document.createElement('img');
            document.body.appendChild(imgNode);
            return {
                setSrcfunction(src{
                    imgNode.src = src;
                }
            }
        })();
        var proxyImage = (function({
            var img = new Image();
            img.onload = function({
                imgFunc.setSrc(this.src);
            }
            return {
                setSrcfunction(src{
                    imgFunc.setSrc('./loading,gif');
                    img.src = src;
                }
            }
        })();
        proxyImage.setSrc('./pic.png');
        復(fù)制代碼

        碰到的:Vue的Proxy、懶加載圖片加占位符、冒泡點(diǎn)擊DOM元素

        參考:javascript 代理模式(通俗易懂)

        策略模式

        策略模式的定義:定義一系列的算法,把他們一個(gè)個(gè)封裝起來(lái),并且使他們可以相互替換。

        策略模式的重心不是如何實(shí)現(xiàn)算法,而是如何組織、調(diào)用這些算法,從而讓程序結(jié)構(gòu)更靈活、可維護(hù)、可擴(kuò)展。

        策略模式的目的:將算法的使用算法的實(shí)現(xiàn)分離開(kāi)來(lái)。

        一個(gè)基于策略模式的程序至少由兩部分組成:

        • 第一個(gè)部分是一組策略類(可變),策略類封裝了具體的算法,并負(fù)責(zé)具體的計(jì)算過(guò)程。
        • 第二個(gè)部分是環(huán)境類Context(不變),Context接受客戶的請(qǐng)求,隨后將請(qǐng)求委托給某一個(gè)策略類。要做到這一點(diǎn),說(shuō)明Context中要維持對(duì)某個(gè)策略對(duì)象的引用。

        原則:開(kāi)放-封閉原則

        /*策略類 A B C就是可以替換使用的算法*/
        var levelOBJ = {
            "A"function(money{
                return money * 4;
            },
            "B" : function(money{
                return money * 3;
            },
            "C" : function(money{
                return money * 2;
            } 
        };
        /*環(huán)境類,維持對(duì)levelOBJ策略對(duì)象的引用,擁有執(zhí)行算法的能力*/
        var calculateBouns =function(level,money{
            return levelOBJ[level](money);
        };

        console.log(calculateBouns('A',10000)); // 40000
        復(fù)制代碼

        Context函數(shù)傳入實(shí)際值,調(diào)用策略,可能同時(shí)調(diào)用多個(gè)策略,這樣可以封裝一函數(shù)循環(huán)調(diào)用策略,然后用Context函數(shù)調(diào)用此封裝的函數(shù)

        在工作中,很多if else,每種條件執(zhí)行不同的算法,其實(shí)可以用到策略模式,比如驗(yàn)證表單

        比如: 
        多種不同登錄方式(賬號(hào)密碼登錄、手機(jī)驗(yàn)證碼登錄和第三方登錄)。為了方便維護(hù)不同的登錄方式,可以把不同的登錄方式封裝成不同的登錄策略。

        驗(yàn)證表單

        不同的人發(fā)不同的工資

        工作中碰到選擇不同下拉框執(zhí)行不同函數(shù)(策略)

        參考:js設(shè)計(jì)模式--策略模式

        建造者模式

        應(yīng)用場(chǎng)景:

        1. 創(chuàng)建時(shí)有很多必填參數(shù)需要驗(yàn)證。
        2. 創(chuàng)建時(shí)參數(shù)求值有先后順序、相互依賴。
        3. 創(chuàng)建有很多步驟,全部成功才能創(chuàng)建對(duì)象。
        class Programmer {
          age: number
          username: string
          color: string
          area: string

          constructor(p) {
            this.age = p.age
            this.username = p.username
            this.color = p.color
            this.area = p.area
          }

          toString() {
            console.log(this)
          }
        }

        class Builder {
          age: number
          username: string
          color: string
          area: string

          build() {
            if (this.age && this.username && this.color && this.area) {
              return new Programmer(this)
            } else {
              throw new Error('缺少信息')
            }
          }

          setAge(age: number) {
            if (age > 18 && age < 36) {
              this.age = age
              return this
            } else {
              throw new Error('年齡不合適')
            }
          }

          setUsername(username: string) {
            if (username !== '小明') {
              this.username = username
              return this
            } else {
              throw new Error('小明不合適')
            }
          }

          setColor(color: string) {
            if (color !== 'yellow') {
              this.color = color
              return this
            } else {
              throw new Error('yellow不合適')
            }
          }

          setArea(area: string) {
            this.area = area
            return this
          }
        }

        // test
        const p = new Builder()
          .setAge(20)
          .setUsername('小紅')
          .setColor('red')
          .setArea('hz')
          .build()
          .toString()

        適配模式

        舉例:Target Adaptee Adapter ,Adapter是需要繼承Target,并在里面調(diào)用Adaptee中的方法。

        形象比擬:Target是目標(biāo)抽象類,實(shí)現(xiàn)插入插口的功能;Adaptee是新的插頭,包含了實(shí)現(xiàn)目標(biāo)的方法;Adapter是implements Target,為了調(diào)用Target方法。這樣,既能保留原功能(原函數(shù)不變),又能執(zhí)行新功能(添加Adaptee Adapter)

        Target是要實(shí)現(xiàn)的目標(biāo)(比如打印日志,這是抽象的方法),如果不用適配模式,就需要重寫(xiě)函數(shù),找到辦法。

        Adaptee是適配者類,也就是插口,在適配器Adapter中,implements來(lái)自于的Target方法(就是新方法,適配的方法,達(dá)到)中調(diào)用Adaptee中的方法。

        Adaptee在Adapter中調(diào)用,Adapter最終是要調(diào)用Adaptee 中需要的具體方法(也就是我們最終要達(dá)到目的使用的方法,此方法可在Target中的抽象方法中實(shí)現(xiàn))。

        場(chǎng)景:
        1.以前開(kāi)發(fā)的接口不滿足需求,比如輸出log存在本地盤(pán)改成存入云盤(pán)
        2.使用第三方提供的組件,但組件接口定義和自己要求的接口定義不同

        面試過(guò)程中,定義Target Adapter Adaptee分別實(shí)現(xiàn)的功能,再套用原理來(lái)實(shí)現(xiàn)。

        用ts實(shí)現(xiàn),這樣能使用interface和implements,更符合面向?qū)ο笳Z(yǔ)言

        優(yōu)點(diǎn)

        • 將目標(biāo)類和適配者類解耦,通過(guò)引入一個(gè)適配器類來(lái)重用現(xiàn)有的適配者類,而無(wú)須修改原有代碼。

        • 增加了類的透明性和復(fù)用性,將具體的實(shí)現(xiàn)封裝在適配者類中,對(duì)于客戶端類來(lái)說(shuō)是透明的,而且提高了適配者的復(fù)用性。

        • 靈活性和擴(kuò)展性都非常好,通過(guò)使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器類,符合開(kāi)閉原則。

        缺點(diǎn)

        • 過(guò)多地使用適配器,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。

        參考:TypeScript 設(shè)計(jì)模式之適配器模式

        模板方法模式

        很好理解,看它能很快理解

        這九種常用的設(shè)計(jì)模式你掌握了嗎

        職責(zé)鏈模式

        應(yīng)用場(chǎng)景:

        1. 多個(gè)處理器 ABC 依次處理同一個(gè)請(qǐng)求,形成一個(gè)鏈條,當(dāng)某個(gè)處理器能處理這個(gè)請(qǐng)求,就不會(huì)繼續(xù)傳遞給后續(xù)處理器了。
        2. 過(guò)濾器 攔截器 處理器。
        const order500 = function (orderType, pay, stock{
          if (orderType === 1 && pay === true) {
            console.log("500 元定金預(yù)購(gòu), 得到 100 元優(yōu)惠券");
            return true;
          } else {
            return false;
          }
        };

        const order200 = function (orderType, pay, stock{
          if (orderType === 2 && pay === true) {
            console.log("200 元定金預(yù)購(gòu), 得到 50 元優(yōu)惠券");
            return true;
          } else {
            return false;
          }
        };

        const orderCommon = function (orderType, pay, stock{
          if ((orderType === 3 || !pay) && stock > 0) {
            console.log("普通購(gòu)買, 無(wú)優(yōu)惠券");
            return true;
          } else {
            console.log("庫(kù)存不夠, 無(wú)法購(gòu)買");
            return false;
          }
        };

        class chain {
          fnFunction
          nextFnFunction

          constructor(fn: Function) {
            this.fn = fn;
            this.nextFn = null;
          }

          setNext(nextFn) {
            this.nextFn = nextFn
          }

          init(...arguments) {
            const result = this.fn(...arguments);
            if (!result && this.nextFn) {
              this.nextFn.init(...arguments); //這里看不懂
            }
          }
        }

        const order500New = new chain(order500);
        const order200New = new chain(order200);
        const orderCommonNew = new chain(orderCommon);

        order500New.setNext(order200New);
        order200New.setNext(orderCommonNew);

        order500New.init(3true500); // 普通購(gòu)買, 無(wú)優(yōu)惠券

        其他參考

        juejin.cn/post/684490… JavaScript 中常見(jiàn)設(shè)計(jì)模式整理

        juejin.cn/post/695342… *

        juejin.cn/post/688138… *

        juejin.cn/post/684490…

        juejin.cn/post/684490…

        最后

        歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
        回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會(huì)很認(rèn)真的解答喲!
        回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
        回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
        如果這篇文章對(duì)你有幫助,在看」是最大的支持
        》》面試官也在看的算法資料《《
        “在看和轉(zhuǎn)發(fā)”就是最大的支持
        瀏覽 44
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩激情视频网站 | 69国产精品 | 北条麻纪久久播放视频 | 男人操女的 | 国产精品无码成人网站视频 | 成人毛片视频免费观看 | 欧美三根一起进三p视频 | 欧美变态口味重另类hd | 国产成人免费 | 男人爽到发出呻吟声 |