<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 17224字,需瀏覽 35分鐘

           ·

          2021-05-09 03:23

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

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

          來源:hannie76327

          https://juejin.cn/post/6953872475537014820

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

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

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

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

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

          單例模式

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

          特點(diǎn):

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

          • 排除全局變量,防止全局變量被重寫

          • 可全局訪問

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

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

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

            缺點(diǎn):

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

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

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

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

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

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

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

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

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

          class寫法

          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ù)寫法

          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)屬性是能夠被人為重寫的,不過不會(huì)像全局變量那樣被無意修改。

          借助閉包

          1. 考慮重寫構(gòu)造函數(shù):當(dāng)對(duì)象第一次被創(chuàng)建以后,重寫構(gòu)造函數(shù),在重寫后的構(gòu)造函數(shù)里面訪問私有變量。
          function A(name){
            var instance = this
            this.name = name
            //重寫構(gòu)造函數(shù)
            A = function (){
                return instance
            }
              //重寫構(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指針指向新地址的問題,實(shí)現(xiàn)原型鏈繼承

          function A(name){
            var instance = this
            this.name = name
           
            //重寫構(gòu)造函數(shù)
            A = function (){
                return instance
            }
            
            // 第一種寫法,這里實(shí)際上實(shí)現(xiàn)了一次原型鏈繼承,如果不想這樣實(shí)現(xiàn),也可以直接指向舊的原型
            A.prototype = this
            // 第二種寫法,直接指向舊的原型
            A.prototype = this.constructor.prototype
            
            instance = new A()
            
            // 調(diào)整構(gòu)造函數(shù)指針,這里實(shí)際上實(shí)現(xiàn)了一次原型鏈繼承,如果不想這樣實(shí)現(xiàn),也可以直接指向原來的原型
            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ù)來保持私有變量
          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

          以上通過閉包的方式可以實(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í)例。主要用來創(chuàng)建同一類對(duì)象。

          簡(jiǎn)單工廠的優(yōu)點(diǎn)在于,你只需要一個(gè)正確的參數(shù),就可以獲取到你所需要的對(duì)象,而無需知道其創(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í)例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應(yīng)該實(shí)例化哪一個(gè)具體產(chǎn)品類。

          抽象工廠模式

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

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

          抽象工廠可以提供多個(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ì)象通知的問題。

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

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

          用雙向綁定來分析此模式:

          雙向綁定維護(hù)4個(gè)模塊:observer監(jiān)聽者、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ù)。

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

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

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

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

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

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

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

          小結(jié)

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

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

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

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

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

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

          publish/emit/點(diǎn)擊/notify 訂閱事件 調(diào)用函數(shù) subscribe/on/addEventListener 監(jiān)聽 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類型來存儲(chǔ)。

          發(fā)布訂閱模式,有個(gè)中介,也可以說是channel,但發(fā)現(xiàn)代碼實(shí)現(xiàn)差不多,只不過發(fā)布訂閱用來寫包含有回調(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ì)象的代碼的話,則可以采用裝飾者模式。
          • 原有方法維持不變,在原有方法上再掛載其他方法來滿足現(xiàn)有需求;函數(shù)的解耦,將函數(shù)拆分成多個(gè)可復(fù)用的函數(shù),再將拆分出來的函數(shù)掛載到某個(gè)函數(shù)上,實(shí)現(xiàn)相同的效果但增強(qiáng)了復(fù)用性。

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

          我覺得可以是函數(shù)封裝原函數(shù)。這樣不改變?cè)瓉?/p>

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

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

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

          代理模式

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

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

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

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

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

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

          常用的虛擬代理:某一個(gè)花銷很大的操作,可以通過虛擬代理的方式延遲到這種需要它的時(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è)封裝起來,并且使他們可以相互替換

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

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

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

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

          原則:開放-封閉原則

          /*策略類 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)(比如打印日志,這是抽象的方法),如果不用適配模式,就需要重寫函數(shù),找到辦法。

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

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

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

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

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

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

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

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

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

          缺點(diǎn)

          • 過多地使用適配器,會(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. 過濾器 攔截器 處理器。
          const order500 = function (orderType, pay, stock{
            if (orderType === 1 && pay === true) {
              console.log("500 元定金預(yù)購, 得到 100 元優(yōu)惠券");
              return true;
            } else {
              return false;
            }
          };

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

          const orderCommon = function (orderType, pay, stock{
            if ((orderType === 3 || !pay) && stock > 0) {
              console.log("普通購買, 無優(yōu)惠券");
              return true;
            } else {
              console.log("庫存不夠, 無法購買");
              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); // 普通購買, 無優(yōu)惠券

          其他參考

          juejin.cn/post/684490… JavaScript 中常見設(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)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕在线观 | 精品欧美一区二区三区四区 | 91 丝袜一区二区三区 | 日韩欧美第一页 | 欧美一级特黄A片免费 |