AOP在職責模式中也有使用,初學設(shè)計模式過程中权薯,AOP是性價比最高的姑躲,在實際開發(fā)中的作用也很重要,學習AOP你可以在不改動原來大量代碼功能模塊的前提下對功能進行改造盟蚣,添加插件黍析,添加功能。比如提交ajax請求提交前屎开,添加驗證功能阐枣,或者修改params。同時也不會修改原有代碼奄抽。
如何理解AOP(切面編程)
AOP中文名叫面向切面編程蔼两。打一個通俗易懂的比喻,現(xiàn)在我們手上有一摞撲克牌如孝,發(fā)牌的過程可以看做是JS的執(zhí)行過程宪哩,一張撲克牌就是一個功能,可能是一個簡單的console.log第晰,也可能是復(fù)雜的http請求锁孟,這張卡牌是??7,如果我想在發(fā)牌過程中連續(xù)拿到??6茁瘦、??7品抽、??8。再不打亂整副牌的前提下甜熔,只需要在??7前加入??6圆恤,??7后面插入??8。當然你可以重寫??7腔稀,直接在牌面上加上新的程序盆昙,不過改變了原有的程序代碼羽历,并不優(yōu)雅;
原來的??7
var ??7 = function(){
console.log(??7);
}
作弊:改寫??7
var ??7= function(){
console.log(??6);
console.log(??7);
console.log(??8);
}
理想的:添加新的卡牌(函數(shù))
var ??6 = function(){
console.log(??6);
}
var ??8 = function(){
console.log(??8);
}
function(){
??6()
??7()
??8()
}
JS中AOP的核心內(nèi)容
Function.prototype.after = function(fn){
var _this = this;
return function(){
var res = _this.apply(this,arguments);
fn.apply(this,arguments);
return res;
}
}
Function.prototype.before = function(fn){
var _this = this;
return function(){
fn.apply(this,arguments);
return _this.apply(this,arguments);
}
}
通過重寫原型鏈淡喜,我們在調(diào)用函數(shù)的時候秕磷,就可以使用原型鏈上的before 和after方法。
下面我們通過一個代碼片段看一看炼团,代碼是怎么運行的澎嚣,可以將代碼在瀏覽器中運行一下,跟著debugger;
瘟芝,多試幾次易桃,更容易理解。
測試代碼講解
Function.prototype.before = function(fn){
var _self = this;
console.log(this)
debugger;
return function () {
//返回值判斷,如果為false那么不執(zhí)行,表示業(yè)務(wù)邏輯執(zhí)行失敗
if(fn.apply(this,arguments) === false){
return false
}
console.log(this)
debugger;
return _self.apply(_self,arguments)
}
}
Function.prototype.after = function(fn){
var _self = this;
console.log(this);
debugger;
return function () {
var result = _self.apply(_self,arguments)
console.log(this)
debugger;
fn.apply(this,arguments)
return result
}
}
function test(val){
debugger;
console.log(val)
}
// 編寫初始處理
function fInter(val){
console.log(val-1)
}
//編寫后續(xù)處理
function fOuter(val){
console.log(val+1)
}
console.log('before')
test.before(fInter) //返回一個為執(zhí)行函數(shù)
console.log('before()')
test.before(fInter)(8);//傳入?yún)?shù)并將上面返回的函數(shù)執(zhí)行
console.log('after()')
test.after(fOuter)(8)//傳入?yún)?shù)并執(zhí)行返回的函數(shù)
test.before(fInter).after(fOuter)(8)//分為兩步锌俱,test.before(flnter)首先返回一個函數(shù)晤郑,
//這個函數(shù)里是需求的順序,然后將這個函數(shù)的作為作用域傳到
//.after(fOuter)中去嚼鹉,作為一個單獨的函數(shù)贩汉,及_self.apply(_self,arguments)進行執(zhí)行。
Function.prototype.after中的result 作用
Function.prototype.after = function(fn){
var _self = this;
console.log(this);
debugger;
return function () {
var result = _self.apply(_self,arguments)
console.log(this)
debugger;
fn.apply(this,arguments)
return result
}
}
test.before(fInter).after(fOuter)(7)
result是為了記錄之前添加好的函數(shù)的集合
打印結(jié)果:
//test(val){
console.log(val)
}
//function(){ 返回加工后的函數(shù):可以稱為addFnbefore()
fnBefore()
text()
}
//funtion(){ 返回最終加工后的函數(shù)也就是接下來要運行的函數(shù):endFn()
addFnbefore()
fnAfter()
}
最后執(zhí)行endFn()
//6
//7
//8
如何打斷
例如我們在提交請求加入了一個fnBefore
用來判斷用戶輸入?yún)?shù)是否有效锚赤,就需要在錯誤的時候打斷提交操作
Function.prototype.before = function(fn){
var _self = this
return function () {
//返回值判斷,如果為false那么不執(zhí)行,表示業(yè)務(wù)邏輯執(zhí)行失敗
if(fn.apply(this,arguments) === false){
return false
}
return _self.apply(_self,arguments)
}
}
Function.prototype.after = function(fn){
var _self = this;
return function () {
var result = _self.apply(_self,arguments)
//after有返回值判斷,如果為false那么不執(zhí)行,表示業(yè)務(wù)邏輯執(zhí)行失敗
if(result === false){
return false;
}
fn.apply(this,arguments)
return result
}
}
如果fn
匹舞,為false
函數(shù)將停止執(zhí)行。
如何不修改Function
的原型鏈前提下實現(xiàn)AOP
持續(xù)更新