在傳統的面向對象語言中,給對象添加功能常常使用繼承的方式,但繼承的方式會帶來問題:當父類改變時,他的所有子類都將隨之改變。
當JavaScript腳本運行時,在一個對象中(或他的原型上)增加行為會影響該對象的所有實例,
裝飾者是一種實現繼承的替代方案,它通過重載方法的形式添加新功能,該模式可以在被裝飾者前面(before)或者後面(after)加上自己的行為以達到特定的目的。
裝飾者模式是為已有功能動態地添加更多功能的一種方式,把每個要裝飾的功能放在單獨的函數裡,然後用該函數包裝所要裝飾的已有函數對象,因此,當需要執行特殊行為的時候,調用代碼就可以根據需要有選擇地、按順序地使用裝飾功能來包裝對象。優點是把類(函數)的核心職責和裝飾功能區分開了。
我們可以定義工具函數,如下:
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; } };
這裡的參數beforeFn、afterFn即為要為原函數擴展新功能的新函數(添加裝飾),它們的唯一區別是執行順序的不同。如果不想污染Function的原型,可以用下面的方法:
var before = function (fn, beforeFn) { return function () { beforeFn.apply(this,arguments); return fn.apply(this,arguments); } }; var after = function (fn, afterFn) { return function () { var ret = fn.apply(this,arguments); afterFn.apply(this,arguments); return ret; } };
例子:給HTTP請求中帶上一個參數防止CSRF攻擊
var ajax = function (type, url, param) { console.log(param); //發送ajax請求代碼略... }; var beforeFn = function (type, url, param) { param.Token = 'Token'; }; ajax = ajax.before(beforeFn); ajax('get','http://...com/userinfo',{name:'SuFa'}); //{ name: 'SuFa', Token: 'Token' }
通過給ajax函數動態裝飾上Token參數,而不是直接在原函數上修改參數,保證了ajax函數仍然是一個純淨的函數,提高了它的可復用性,它可在無需做任何修改的情況下直接拿到別的項目中使用。
例子:表單驗證(把驗證輸入和表單提交的代碼分離開來,然後動態的把驗證輸入功能裝飾到表單提交之前,這樣一來,我們就可以把驗證輸入部分寫成一個插件的形式,用在不同的項目中)
//驗證輸入函數 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('http://xxx.com/login',param); }; formSubmit = formSubmit.before(validata); submitBtn.onclick = function(){ formSubmit(); };
參考文獻: 《JavaScript模式》 《JavaScript設計模式與開發實踐》
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持。