摘要:用戶名不能為空密碼不能為空校驗(yàn)未通過使用優(yōu)化代碼返回的情況直接,不再執(zhí)行后面的原函數(shù)用戶名不能為空密碼不能為空
本文是《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》的學(xué)習(xí)筆記,例子來源于書中,對(duì)于設(shè)計(jì)模式的看法,推薦看看本書作者的建議。
什么是裝飾者模式?給對(duì)象動(dòng)態(tài)增加職責(zé)的方式成為裝飾者模式。
裝飾者模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在運(yùn)行程序期間給對(duì)象動(dòng)態(tài)地添加職責(zé)。這是一種輕便靈活的做法,裝飾者是一種“即付即用”的方式,比如天冷了就多穿一件外套。
裝飾函數(shù)想要為函數(shù)添加一些功能,最簡單粗暴的方式就是直接改寫該函數(shù),但是這是最差的辦法,直接違反了開放——封閉原則。
var a = function(){ alert(1) } // 改成 var a = function(){ alert(1) alert(2) }
很多時(shí)候我們不想碰原函數(shù),也許原函數(shù)是其他同事編寫的,甚至在一個(gè)古老的項(xiàng)目中,這個(gè)函數(shù)的源代碼被隱藏在一個(gè)我們不愿觸碰的陰暗角落里?,F(xiàn)在需要不改變?cè)创a的情況下,給函數(shù)增加功能。
我們通過保存原引用的方式改寫某個(gè)函數(shù)。
var a = function(){ alert(1) } var _a = a a = function(){ _a() alert(2) } a()
這是實(shí)際開發(fā)中很常見的一個(gè)做法,比如我們想給 window 綁定 onload 事件,但是又不確定這個(gè)事件是不是已經(jīng)被其他人綁定過,為了避免覆蓋掉之前的 window.onload 函數(shù)中的行為,先保存 window.onload,把它放入新的 window.onload。
window.onload = function(){ alert(1) } var _onload = window.onload || function(){} window.onload = funtion(){ _onload() alert(2) }
這樣的代碼是符合封閉——開放原則,我們?cè)谠黾有鹿δ艿臅r(shí)候確實(shí)沒有修改原來的代碼,但是這種方式存在兩個(gè)問題:
必須維護(hù) _onload 這個(gè)中間變量,雖然看起來不起眼,但是如果函數(shù)裝飾鏈較長,或者需要裝飾的函數(shù)變多,這些中間變量的數(shù)量也會(huì)越來越多。
其實(shí)還遇到了 this 被劫持的問題,在 window.onload 的例子中沒有這個(gè)煩惱,因?yàn)檎{(diào)用 _onload 的時(shí)候 this 也指向 window,跟調(diào)用 window.onload 的時(shí)候一樣。
用 AOP 裝飾函數(shù)AOP(Aspect Oriented Programming)面向切面編程的主要作用是:把一些跟核心業(yè)務(wù)邏輯無關(guān)的功能抽離出來,這些跟業(yè)務(wù)邏輯無關(guān)的功能通常包括日志統(tǒng)計(jì)、安全控制、異常處理等。把這些功能抽離出來以后,再通過“動(dòng)態(tài)織入”的方式摻入業(yè)務(wù)邏輯模塊中。這樣的好處首先是可以保持業(yè)務(wù)邏輯模塊的純凈和高內(nèi)聚性,其次是可以很方便地復(fù)用日志統(tǒng)計(jì)等功能模塊。
首先給出 Function.prototype.before 和 Function.prototype.after 方法:
Function.prototype.before = function(beforefn){ // 保存原函數(shù)的引用 var _self = this // 返回包含原函數(shù)和新函數(shù)的“代理函數(shù)” return function(){ // 執(zhí)行新函數(shù),保證this不被劫持, // 新函數(shù)接受的參數(shù)也會(huì)被原封不動(dòng)地傳入原函數(shù), // 新函數(shù)在原函數(shù)之前執(zhí)行 beforefn.apply(this,arguments) return _self.apply(this.arguments) } } Function.prototype.after = function(afterfn){ var _self = this return function(){ var ret = _self.apply(this,arguments) afterfn.apply(this,arguments) return ret } }
“代理函數(shù)”只是結(jié)構(gòu)上像代理而已,并不承擔(dān)代理的職責(zé)(比如控制對(duì)象的訪問),它的工作是把請(qǐng)求分別轉(zhuǎn)發(fā)給新添加的函數(shù)和原函數(shù),且負(fù)責(zé)保證它們的執(zhí)行順序。
再回到 window.onload 的例子中,用 Function.prototype.after 來增加新事件:
window.onload = function(){ alert(1) } window.onload = (window.onload || function(){}).after(function(){ alert(2) }).after(function(){ alert(3) })AOP 的應(yīng)用實(shí)例
(1)數(shù)據(jù)統(tǒng)計(jì)上報(bào)
showLogin 函數(shù)既要負(fù)責(zé)打開浮層,又要負(fù)責(zé)數(shù)據(jù)上報(bào),兩個(gè)功能耦合在一個(gè)函數(shù)里,使用 AOP 分離:
(2) 插件式表單驗(yàn)證
用戶名: 密碼:
formatSubmit 函數(shù)承擔(dān)了兩個(gè)職責(zé),除了提交ajax請(qǐng)求,還要驗(yàn)證用戶輸入的合法性。我們把校驗(yàn)輸入的邏輯放到validata函數(shù)中,并約定當(dāng)validata函數(shù)返回false的時(shí)候表示校驗(yàn)未通過。
var validata = function(){ if ( username.value === "" ){ alert ( "用戶名不能為空" ); return false; } if ( password.value === "" ){ alert ( "密碼不能為空" ); return false; } } var formSubmit = function(){ if ( validata() === false ){ // 校驗(yàn)未通過 return; } var param = { username: username.value, password: password.value } ajax( "http:// xxx.com/login", param ); } submitBtn.onclick = function(){ formSubmit(); }
使用AOP優(yōu)化代碼
Function.prototype.before = function( beforefn ){ var __self = this; return function(){ if ( beforefn.apply( this, arguments ) === false ){ // beforefn 返回false 的情況直接return,不再執(zhí)行后面的原函數(shù) return; } return __self.apply( this, arguments ); } } 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(); }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108950.html
摘要:聲明這個(gè)系列為閱讀設(shè)計(jì)模式與開發(fā)實(shí)踐曾探著一書的讀書筆記裝飾者模式的定義裝飾者模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。裝飾者模式的作用就是為對(duì)象動(dòng)態(tài)的加入某些行為。 聲明:這個(gè)系列為閱讀《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 ----曾探@著一書的讀書筆記 裝飾者模式的定義: 裝飾者(decorator)模式能...
摘要:下裝飾者的實(shí)現(xiàn)了解了裝飾者模式和的概念之后,我們寫一段能夠兼容的代碼來實(shí)現(xiàn)裝飾者模式原函數(shù)拍照片定義函數(shù)裝飾函數(shù)加濾鏡用裝飾函數(shù)裝飾原函數(shù)這樣我們就實(shí)現(xiàn)了抽離拍照與濾鏡邏輯,如果以后需要自動(dòng)上傳功能,也可以通過函數(shù)來添加。 showImg(https://segmentfault.com/img/bVbueyz?w=852&h=356); 什么是裝飾者模式 當(dāng)我們拍了一張照片準(zhǔn)備發(fā)朋友...
摘要:設(shè)計(jì)模式裝飾者模式何為裝飾者,意思就是,在不影響對(duì)象主功能的情況下,再添加一些額外的功能,使對(duì)象具備更多的功能。與繼承相比,裝飾者是一種更靈活輕便的做法。 javascript設(shè)計(jì)模式 --- 裝飾者模式 何為裝飾者,意思就是,在不影響對(duì)象主功能的情況下,再添加一些額外的功能,使對(duì)象具備更多的功能。與繼承相比,裝飾者是一種更靈活輕便的做法。下面我們看看javascript里裝飾者模式 ...
摘要:裝飾者模式定義裝飾者模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。 裝飾者模式 定義 : 裝飾者(decorator)模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。 在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)地添加一些額外職責(zé) 特點(diǎn) : 可以動(dòng)態(tài)的...
摘要:裝飾者模式裝飾者模式提供比繼承更有彈性的替代方案。裝飾者用于包裝同接口的對(duì)象,用于通過重載方法的形式添加新功能,該模式可以在被裝飾者的前面或后面加上自己的行為以達(dá)到特定的目的。簡單的理解給對(duì)象動(dòng)態(tài)添加職責(zé)的方式稱為裝飾著模式。 裝飾者模式 裝飾者模式提供比繼承更有彈性的替代方案。裝飾者用于包裝同接口的對(duì)象,用于通過重載方法的形式添加新功能,該模式可以在被裝飾者的前面或后面加上自己的行為...
摘要:單體模式有以下優(yōu)點(diǎn)用來劃分命名空間,減少全局變量數(shù)量。通常我們使用操作符創(chuàng)建單體模式的三種選擇,讓構(gòu)造函數(shù)總返回最初的對(duì)象使用全局對(duì)象來存儲(chǔ)該實(shí)例不推薦,容易全局污染。實(shí)現(xiàn)該工廠模式并不困難,主要是要找到能夠穿件所需類型對(duì)象的構(gòu)造函數(shù)。 介紹 最近開始給自己每周訂個(gè)學(xué)習(xí)任務(wù),學(xué)習(xí)結(jié)果反饋為一篇文章的輸出,做好學(xué)習(xí)記錄。 這一周(02.25-03.03)我定的目標(biāo)是《JavaScri...
閱讀 1457·2021-11-22 13:54
閱讀 4376·2021-09-22 15:56
閱讀 1828·2021-09-03 10:30
閱讀 1326·2021-09-03 10:30
閱讀 2093·2019-08-30 15:55
閱讀 1859·2019-08-30 14:13
閱讀 2066·2019-08-29 15:19
閱讀 2374·2019-08-28 18:13