這篇文章將為大家詳細(xì)講解有關(guān)JavaScript中裝飾者模式與AOP的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到昂昂溪網(wǎng)站設(shè)計(jì)與昂昂溪網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:網(wǎng)站建設(shè)、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、申請(qǐng)域名、網(wǎng)頁(yè)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋昂昂溪地區(qū)。什么是裝飾者模式
當(dāng)我們拍了一張照片準(zhǔn)備發(fā)朋友圈時(shí),許多小伙伴會(huì)選擇給照片加上濾鏡。同一張照片、不同的濾鏡組合起來(lái)就會(huì)有不同的體驗(yàn)。這里實(shí)際上就應(yīng)用了裝飾者模式:是通過(guò)濾鏡裝飾了照片。在不改變對(duì)象(照片)的情況下動(dòng)態(tài)的為其添加功能(濾鏡)。
需要注意的是:由于 JavaScript 語(yǔ)言動(dòng)態(tài)的特性,我們很容易就能改變某個(gè)對(duì)象(JavaScript 中函數(shù)是一等公民)。但是我們要盡量避免直接改寫(xiě)某個(gè)函數(shù),這會(huì)導(dǎo)致代碼的可維護(hù)性、可擴(kuò)展性變差,甚至?xí)廴酒渌麡I(yè)務(wù)。
什么是 AOP
想必大家對(duì)"餐前洗手、飯后漱口"都不陌生。這句標(biāo)語(yǔ)其實(shí)就是 AOP 在生活中的例子:吃飯這個(gè)動(dòng)作相當(dāng)于切點(diǎn),我們可以在這個(gè)切點(diǎn)前、后插入其它如洗手等動(dòng)作。
AOP(Aspect-Oriented Programming):面向切面編程,是對(duì) OOP 的補(bǔ)充。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,也可以隔離業(yè)務(wù)無(wú)關(guān)的功能比如日志上報(bào)、異常處理等,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高業(yè)務(wù)無(wú)關(guān)的功能的復(fù)用性,也就提高了開(kāi)發(fā)的效率。
在 JavaScript 中,我們可以通過(guò)裝飾者模式來(lái)實(shí)現(xiàn) AOP,但是兩者并不是一個(gè)維度的概念。 AOP 是一種編程范式,而裝飾者是一種設(shè)計(jì)模式。
ES3 下裝飾者的實(shí)現(xiàn)
了解了裝飾者模式和 AOP 的概念之后,我們寫(xiě)一段能夠兼容 ES3 的代碼來(lái)實(shí)現(xiàn)裝飾者模式:
// 原函數(shù) var takePhoto =function(){ console.log('拍照片'); } // 定義 aop 函數(shù) var after=function( fn, afterfn ){ return function(){ let res = fn.apply( this, arguments ); afterfn.apply( this, arguments ); return res; } } // 裝飾函數(shù) var addFilter=function(){ console.log('加濾鏡'); } // 用裝飾函數(shù)裝飾原函數(shù) takePhoto=after(takePhoto,addFilter); takePhoto();
這樣我們就實(shí)現(xiàn)了抽離拍照與濾鏡邏輯,如果以后需要自動(dòng)上傳功能,也可以通過(guò)aop函數(shù)after來(lái)添加。
ES5 下裝飾者的實(shí)現(xiàn)
在 ES5 中引入了Object.defineProperty,我們可以更方便的給對(duì)象添加屬性:
let takePhoto = function () { console.log('拍照片'); } // 給 takePhoto 添加屬性 after Object.defineProperty(takePhoto, 'after', { writable: true, value: function () { console.log('加濾鏡'); }, }); // 給 takePhoto 添加屬性 before Object.defineProperty(takePhoto, 'before', { writable: true, value: function () { console.log('打開(kāi)相機(jī)'); }, }); // 包裝方法 let aop = function (fn) { return function () { fn.before() fn() fn.after() } } takePhoto = aop(takePhoto) takePhoto()
基于原型鏈和類(lèi)的裝飾者實(shí)現(xiàn)
我們知道,在 JavaScript 中,函數(shù)也好,類(lèi)也好都有著自己的原型,通過(guò)原型鏈我們也能夠很方便的動(dòng)態(tài)擴(kuò)展,以下是基于原型鏈的寫(xiě)法:
class Test { takePhoto() { console.log('拍照'); } } // after AOP function after(target, action, fn) { let old = target.prototype[action]; if (old) { target.prototype[action] = function () { let self = this; fn.bind(self); fn(handle); } } } // 用 AOP 函數(shù)修飾原函數(shù) after(Test, 'takePhoto', () => { console.log('添加濾鏡'); }); let t = new Test(); t.takePhoto();
使用 ES7 修飾器實(shí)現(xiàn)裝飾者
在 ES7 中引入了@decorator 修飾器的提案,參考阮一峰的文章。修飾器是一個(gè)函數(shù),用來(lái)修改類(lèi)的行為。目前Babel轉(zhuǎn)碼器已經(jīng)支持。注意修飾器只能裝飾類(lèi)或者類(lèi)屬性、方法。三者的具體區(qū)別請(qǐng)參考 MDN Object.defineProperty ;而 TypeScript 的實(shí)現(xiàn)又有所不同:TypeScript Decorator。
接下來(lái)我們通過(guò)修飾器來(lái)實(shí)現(xiàn)對(duì)方法的裝飾:
function after(target, key, desc) { const { value } = desc; desc.value = function (...args) { let res = value.apply(this, args); console.log('加濾鏡') return res; } return desc; } class Test{ @after takePhoto(){ console.log('拍照') } } let t = new Test() t.takePhoto()
可以看到,使用修飾器的代碼非常簡(jiǎn)潔明了。
場(chǎng)景:性能上報(bào)
裝飾者模式可以應(yīng)用在很多場(chǎng)景,典型的場(chǎng)景是記錄某異步請(qǐng)求請(qǐng)求耗時(shí)的性能數(shù)據(jù)并上報(bào):
function report(target, key, desc) { const { value } = desc; desc.value = async function (...args) { let start = Date.now(); let res = await value.apply(this, args); let millis = Date.now()-start; // 上報(bào)代碼 return res; } return desc; } class Test{ @report getData(url){ // fetch 代碼 } } let t = new Test() t.getData()
這樣使用@report修飾后的代碼就會(huì)上報(bào)請(qǐng)求所消耗的時(shí)間。擴(kuò)展或者修改report函數(shù)不會(huì)影響業(yè)務(wù)代碼,反之亦然。
場(chǎng)景:異常處理
我們可以對(duì)原有代碼進(jìn)行簡(jiǎn)單的異常處理,而無(wú)需侵入式的修改:
function handleError(target, key, desc) { const { value } = desc; desc.value = async function (...args) { let res; try{ res = await value.apply(this, args); }catch(err){ // 異常處理 logger.error(err) } return res; } return desc; } class Test{ @handleError getData(url){ // fetch 代碼 } } let t = new Test() t.getData()
通過(guò)以上兩個(gè)示例我們可以看到,修飾器的定義很簡(jiǎn)單,功能卻非常強(qiáng)大。
關(guān)于“JavaScript中裝飾者模式與AOP的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
新聞標(biāo)題:JavaScript中裝飾者模式與AOP的示例分析-創(chuàng)新互聯(lián)
當(dāng)前網(wǎng)址:http://aaarwkj.com/article2/dppjoc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、軟件開(kāi)發(fā)、外貿(mào)建站、動(dòng)態(tài)網(wǎng)站、網(wǎng)站制作、電子商務(wù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容