<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 裝飾者模式 給對象動態地增加職責的方式稱為裝飾者模式。 裝飾者模式能夠在不改變對象自身的基礎上,在程序運行期間給對象動態地添加職責。跟繼承相比,裝飾者是一種更輕便靈活的做法,這是一種“即用即付”的方式。 ## 模擬傳統面向對象語言的裝飾者模式 ```javascript var Plan = function(){}; Plan.prototype.fire = function(){ console.log('普通子彈'); }; var MissileDecorator = function(plan){ this.plan = plan; }; MissileDecorator.prototype.fire = function(){ this.plan.fire(); console.log('導彈'); }; var AtomDecorator = function(plan){ this.plan = plan; }; AtomDecorator.prototype.fire = function(){ this.plan.fire(); console.log('原子彈'); }; var plan = new Plan(); plan = new MissileDecorator(plan); plan = new AtomDecorator(plan); plan.fire(); ``` 這種給對象動態增加職責的方式,并沒有真正地改動對象自身,而是將對象放入另一個對象之中,這些對象以一條鏈的方式進行引用,形成一個聚合對象。這些對象都擁有相同的接口,當請求到達鏈中的某個對象時,這個對象會執行自身的操作,隨后把請求轉發給鏈中的下一個對象。 ## 裝飾者也是包裝器 裝飾者模式將一個對象嵌入另一個對象之中,實際上相當于這個對象被另一個對象包裝起來,形成一條包裝鏈。 ## 回到JavaScript的裝飾者 ```javascript var plan = { fire: function(){ console.log('普通子彈'); } }; var missilDecorator = function(){ console.log('導彈'); }; var atomDecorator = function(){ console.log('原子彈'); }; var fire1 = plane.fire; plan.fire = function(){ fire1(); missilDecorator(); }; var fire2 = plan.fire; plan.fire = function(){ fire2(); atomDecorator(); }; plan.fire(); ``` ## 裝飾函數 通過保存原引用的方式就可以改寫某個函數 ```javascript var a = function(){ alert(1); }; var _a = a; a = function(){ _a(); alert(2); }; a(); ``` 但是這種方式存在兩個問題: - 必須維護一個中間變量,如果裝飾函數的裝飾鏈較長,或者需要裝飾的函數變多,這些中間變量的數量也會越來越多。 - 還會遇到`this`被劫持的問題。 ## 用AOP裝飾函數 給出`Function.prototype.before`和`Function.prototype.after`方法 ```javascript Function.prototype.before = function(beforeFn){ var _self = this; // 保存原函數的引用 return function(){ // 返回包含了原函數和新函數的“代理”函數 beforefn.apply(this, arguments); // 執行新函數,且保證this不被劫持,新函數接受的參數也會原封不動地傳入原函數,新函數在原函數之前執行 return _self.apply(this, arguments); // 執行原函數并返回原函數的執行結果,并且保證this不被劫持 } }; Function.prototype.after = function(afterFn){ var _self = this; return function(){ var ret = _self.apply(this, arguments); afterFn.apply(this, arguments); return ret; } }; ``` `Function.prototype.before`接受一個函數當作參數,這個函數即為新添加的函數,它裝載了新添加的功能。 接下來把當前的`this`保存起來,這個`this`指向原函數,然后返回一個“代理”函數,這個“代理”函數只是結構上像代理而已,并不承擔代理的職責。它的工作是把請求分別轉發給新添加的函數和原函數,且負責保證它們的執行順序,讓新添加的函數在原函數之前執行,這樣就實現了動態裝飾的效果。 ## AOP的應用實例 用`AOP`裝飾函數的技巧在實際開發中非常有用。不論是業務代碼的編寫,還是在框架層面,都可以把行為依照職責分成粒度更細的函數,隨后通過裝飾把它們合并到一起,有助于編寫一個松耦合和高復用性的系統。 ### 數據統計上報 ```javascript Function.prototype.after = function(afterFn){ var _self = this; return function(){ var ret = _self.apply(this, arguments); afterFn.apply(this, arguments); return ret; } }; var showLogiun = function(){ console.log('打開登錄浮層'); }; var log = function(){ console.log('上報數據'); }; showLogin = showLogin.after(log); document.getElementById('login').onclick = showLogin; ``` ### 用AOP動態改變函數的參數 ```javascript Function.prototype.before = function(beforeFn){ var _self = this; return function(){ beforefn.apply(this, arguments); return _self.apply(this, arguments); } }; var func = function(param){ console.log(param); // 輸出:{a: 'a', b:'b'} }; func = func.before(function(param){ param.b = 'b'; }); func({a: 'a'}); ``` ### 插件式的表單驗證 ```javascript Function.prototype.before = function(beforeFn){ var _self = this; return function(){ if(beforefn.apply(this, arguments) === false){ return; }; return _self.apply(this, arguments); } }; var validata = function(){ if(username.value === ''){ alert('不能為空'); return false; } if(password.value === ''){ alert('不能為空'); return false; } }; var formSubmit = function(){ var param = { username: username.value, password: password.value }; ajax('....'); }; formSubmit = formSubimt.before(validata); submitBtn.onclick = function(){ formSubmit(); }; ``` 函數通過`Function.prototype.before`或者`Function.prototype.after`被裝飾之后,返回的實際上是一個新的函數,如果在原函數上保存了一些屬性,那么這些屬性會丟失。 這種裝飾方式也疊加了函數的作用域,如果裝飾的鏈條過長,性能上也會受到一些影響。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看