在傳統的面向對象語言中,給對象添加功能常常使用繼承的方式,但繼承的方式會帶來問題:當父類改變時,他的所有子類都將隨之改變。
當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設計模式與開發實踐》
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持。