javascript AOP的實現

來源:互聯網
上載者:User


以前學習java的Spring架構時,這是個很強大的東西,用於實現調用者和被調用者之間的解耦。雖然在JS中也提供了call與apply動態改變調用者,但在複雜的UI組件中,這是遠遠不夠了。前段時間也在無憂中看到一個類似的需求,說要“如何繼承自己”,辭不達意,亂七八糟,但回貼都是精華,讓我見識到AOP在JS的運用,逐研究了下這個東西。

以下是我最初的實現,它取用的方式是在某個執行個體方法的前面或後面織入通知函數。

       // pointcut: 織入點對象 ,target:被織入的對象 ,method:被織入的方法名字 ,advice: 通知函數      function Person(){        this.say =  function(){          alert("高談闊論!");        }        this.cry =  function(){          alert("鬼哭神嚎!");        }        this.round =  function(){          alert("天地無用!");        }      }      Aspects = function(){};      Aspects.prototype={        before:function(target,method,advice){          (advice)();          for(var i in target){            if(i == method){              target[i]();            };          };        },        after:function(target,method,advice){          for(var i in target){            if(i == method){              target[i]();            };          };          (advice)();        },        around:function(target,method,advice){          (advice)();          for(var i in target){            if(i == method){              target[i]();            };          };          (advice)();        }      }      window.onload = function(){        var t = new Person;        var a = new Aspects;        a.before(t,"say",function(){alert("一馬當先")})        a.after(t,"cry",function(){alert("事後孔明")})        a.around(t, "round", function(){alert("十面埋伏")})        alert("===========================");        t.say();      }

<br /><script type="text/javascript"><br /> function Person(){<br /> this.say = function(){<br /> alert("高談闊論!");<br /> }<br /> this.cry = function(){<br /> alert("鬼哭神嚎!");<br /> }<br /> this.round = function(){<br /> alert("天地無用!");<br /> }<br /> }<br /> Aspects = function(){};<br /> Aspects.prototype={<br /> before:function(target,method,advice){<br /> (advice)();<br /> for(var i in target){<br /> if(i == method){<br /> target[i]();<br /> };<br /> };<br /> },<br /> after:function(target,method,advice){</p><p> for(var i in target){<br /> if(i == method){<br /> target[i]();<br /> };<br /> };<br /> (advice)();<br /> },<br /> around:function(target,method,advice){<br /> (advice)();<br /> for(var i in target){<br /> if(i == method){<br /> target[i]();<br /> };<br /> };<br /> (advice)();<br /> }<br /> }<br /> window.onload = function(){<br /> var t = new Person;<br /> var a = new Aspects;<br /> a.before(t,"say",function(){alert("一馬當先")})<br /> a.after(t,"cry",function(){alert("事後孔明")})<br /> a.around(t, "round", function(){alert("十面埋伏")})<br /> alert("===========================");<br /> t.say();<br /> }<br /></script><br />

運行代碼

非常糟糕!它馬上就執行了,而不等到我們調用t.say()時執行!改變一下思路,把通知函數織入執行個體方法中,然後在這個被織入的方法中執行原來的邏輯與新織入的邏輯!

 function Person(){        this.say =  function(name){          alert("我的名字叫做"+name+"……");        }      }      Aspects = function(){};      Aspects.prototype={        before:function(target,method,advice){          var original  = target[method];          target[method] = function(){            (advice)();            original();          }          return target        },        after:function(target,method,advice){          var original  = target[method];          target[method] = function(){            original();            (advice)();          }          return target        },        around:function(target,method,advice){          var original  = target[method];          target[method] = function(){            (advice)();            original();            (advice)();          }          return target        }      }      window.onload = function(){        var t = new Person;        var a = new Aspects;        t = a.before(t,"say",function(){alert("請你介紹一下自己!")});        alert("===========================")        t.say("司徒正美");      }

<br /> <script type="text/javascript"><br /> function Person(){<br /> this.say = function(name){<br /> alert("我的名字叫做"+name+"……");<br /> }<br /> }<br /> Aspects = function(){};<br /> Aspects.prototype={<br /> before:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> (advice)();<br /> original();<br /> }<br /> return target<br /> },<br /> after:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> original();<br /> (advice)();<br /> }<br /> return target<br /> },<br /> around:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> (advice)();<br /> original();<br /> (advice)();<br /> }<br /> return target<br /> }<br /> }<br /> window.onload = function(){<br /> var t = new Person;<br /> var a = new Aspects;<br /> t = a.before(t,"say",function(){alert("請你介紹一下自己!")});<br /> alert("===========================")<br /> t.say("司徒正美");<br /> }<br /> </script><br />

運行代碼

發現不能傳入參數,我們可以用apply來綁定參數。之所以選擇apply,是因為它比call更靈活。

 /******************略**********************/     before:function(target,method,advice){           var original  = target[method];          target[method] = function(){            (advice)();             original.apply(target, arguments);          }          return target        },/******************略**********************/

<br /> <script type="text/javascript"><br /> function Person(){<br /> this.say = function(name,lang){<br /> alert("我的名字叫做"+name+",專註於"+lang+"……");<br /> }<br /> }<br /> Aspects = function(){};<br /> Aspects.prototype={<br /> before:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> (advice)();<br /> original.apply(target, arguments);<br /> }<br /> return target<br /> },<br /> after:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> original.apply(target, arguments);<br /> (advice)();<br /> }<br /> return target<br /> },<br /> around:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> (advice)();<br /> original.apply(target, arguments);<br /> (advice)();<br /> }<br /> return target<br /> }<br /> }<br /> window.onload = function(){<br /> var t = new Person;<br /> var a = new Aspects;<br /> t = a.before(t,"say",function(){alert("請你介紹一下自己!")});<br /> alert("===========================")<br /> t.say("司徒正美","javascript");<br /> }<br /> </script><br />

運行代碼

最後放出一個現實點的例子吧,看看你能聯想到什嗎?!

<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <meta http-equiv="X-UA-Compatible" content="IE=Edge"><br /> <script type="text/javascript"><br /> function voice(){<br /> alert("救命啊!");<br /> }<br /> Aspects = function(){};<br /> Aspects.prototype={<br /> before:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> (advice)();<br /> original.apply(target, arguments);<br /> }<br /> return target<br /> },<br /> after:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> original.apply(target, arguments);<br /> (advice)();<br /> }<br /> return target<br /> },<br /> around:function(target,method,advice){<br /> var original = target[method];<br /> target[method] = function(){<br /> (advice)();<br /> original.apply(target, arguments);<br /> (advice)();<br /> }<br /> return target<br /> }<br /> }<br /> window.onload = function(){<br /> var bn = document.getElementById("bn");<br /> var a = new Aspects;<br /> a.after(bn,"onclick",function(){alert("HELP!HELP!")});<br /> }<br /> </script><br /> <title>非法修改button的onclick事件</title><br /> </head><br /> <body><br /> <input onclick="voice()" type="button" id="bn" value="動我就叫人來"><br /> </body><br /></html><br />

運行代碼

想到了嗎?聯想一下我們部落格園,可能以這個作例子有點不妥……它為了安全在我們點擊提交表單時,都會對我們輸入的內容進行正則替換,把一些危險的代碼過濾掉,或換成&gt;、&lt;之類不能啟動並執行編碼。如果我們用AOP hack一下這個提交按鈕,在部落格園替換完後我們再替換回去,就可以做出一些不為人齒的事來,當然不希望大家這樣做……我們應該用到正當的途徑上,如Ext就大量利用AOP來增強組件的功能了。又譬如,我們編寫了一個複雜的Grid控制項,但無法事先預計哪些方法需要觸發事件。這種情況下,你可以直接攔截控制項的某些方法來類比事件處理。另,在許可權驗證、內容傳輸、錯誤處理、調試、記錄跟蹤等方面,AOP都有一番作用,我們應該好好掌握這一設計模式,畢竟它被稱之為OOP的延伸與補充。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.