輕松掌握J(rèn)avaScript裝飾者模式
在傳統(tǒng)的面向?qū)ο笳Z言中,給對象添加功能常常使用繼承的方式,但繼承的方式會帶來問題:當(dāng)父類改變時,他的所有子類都將隨之改變。
當(dāng)JavaScript腳本運(yùn)行時,在一個對象中(或他的原型上)增加行為會影響該對象的所有實(shí)例,
裝飾者是一種實(shí)現(xiàn)繼承的替代方案,它通過重載方法的形式添加新功能,該模式可以在被裝飾者前面(before)或者后面(after)加上自己的行為以達(dá)到特定的目的。
裝飾者模式是為已有功能動態(tài)地添加更多功能的一種方式,把每個要裝飾的功能放在單獨(dú)的函數(shù)里,然后用該函數(shù)包裝所要裝飾的已有函數(shù)對象,因此,當(dāng)需要執(zhí)行特殊行為的時候,調(diào)用代碼就可以根據(jù)需要有選擇地、按順序地使用裝飾功能來包裝對象。優(yōu)點(diǎn)是把類(函數(shù))的核心職責(zé)和裝飾功能區(qū)分開了。
我們可以定義工具函數(shù),如下:
Function.prototype.before = function (beforeFn) { var self = this; //保存原函數(shù)的引用 return function () { //返回包含了新函數(shù)和原函數(shù)的代理函數(shù) beforeFn.apply(this,arguments); //執(zhí)行新函數(shù),且保證this不被劫持 return self.apply(this,arguments); //執(zhí)行原函數(shù),并返回原函數(shù)的執(zhí)行結(jié)果,并保證this不被劫持 } }; Function.prototype.after = function (afterFn) { var self = this; return function () { var ret = self.apply(this,arguments); afterFn.apply(this,arguments); return ret; } };
這里的參數(shù)beforeFn、afterFn即為要為原函數(shù)擴(kuò)展新功能的新函數(shù)(添加裝飾),它們的唯一區(qū)別是執(zhí)行順序的不同。如果不想污染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請求中帶上一個參數(shù)防止CSRF攻擊
var ajax = function (type, url, param) { console.log(param); //發(fā)送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函數(shù)動態(tài)裝飾上Token參數(shù),而不是直接在原函數(shù)上修改參數(shù),保證了ajax函數(shù)仍然是一個純凈的函數(shù),提高了它的可復(fù)用性,它可在無需做任何修改的情況下直接拿到別的項(xiàng)目中使用。
例子:表單驗(yàn)證(把驗(yàn)證輸入和表單提交的代碼分離開來,然后動態(tài)的把驗(yàn)證輸入功能裝飾到表單提交之前,這樣一來,我們就可以把驗(yàn)證輸入部分寫成一個插件的形式,用在不同的項(xiàng)目中)
//驗(yàn)證輸入函數(shù) var validata = function () { if(username.value === ''){ alert('用戶名不能為空'); return false; } if(password.value === ''){ alert('密碼不能為空'); return false; } }; //表單提交函數(shù) 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(); };
參考文獻(xiàn): 《JavaScript模式》 《JavaScript設(shè)計模式與開發(fā)實(shí)踐》
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
微信小程序與axios組成網(wǎng)絡(luò)層封裝過程詳解
小程序在網(wǎng)絡(luò)層提供的API是能夠完成一個程序與服務(wù)端交互的完整鏈路,但需要大量的定制化代碼,才能實(shí)現(xiàn)請求攔截和響應(yīng)攔截,不太符合大多數(shù)開發(fā)者的使用習(xí)慣,對于前端開發(fā)者來說,網(wǎng)絡(luò)層還得是axios2023-02-02JavaScript組件焦點(diǎn)與頁內(nèi)錨點(diǎn)間傳值的方法
這篇文章主要介紹了JavaScript組件焦點(diǎn)與頁內(nèi)錨點(diǎn)間傳值的方法,涉及輸入框與錨點(diǎn)的操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-02-0210個必備的JavaScript?async/await工具函數(shù)分享
當(dāng)談到異步編程時,async/await是JavaScript中常用的功能之一,本文為大家整理了10個常用的await和async函數(shù)示例,感興趣的小伙伴可以參考一下2023-12-12javascript獲取元素文本內(nèi)容的通用函數(shù)
獲取元素文本內(nèi)容的通用函數(shù),思路很好值得參考。2009-12-12javascript使用 concat 方法對數(shù)組進(jìn)行合并的方法
這篇文章主要介紹了javascript使用 concat 方法對數(shù)組進(jìn)行合并的方法,本文介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友一起看看吧2016-09-09