面向切面的編程(AOP)還是有點意思的,可以在不修改原有代碼的情況下增加新功能。有一些js架構實現AOP功能,但是有些時候我們並不能依賴於架構寫程式(架構可能很笨重),我們需要自己實現一些適合我們的功能模組。下面是我自己實現的js AOP,實現了before和after功能,僅供拋磚。
如下是aspect.js,是實現AOP的全過程。
(function(window, undefined){
function aspect(type){
return function(target, methodName, advice){
var exist = target[methodName],
dispatcher;
if( !exist || exist.target != target ){
dispatcher = target[methodName] = function(){
// before methods
var beforeArr = dispatcher.before;
var args = arguments;
for(var l = beforeArr.length ; l--; ){
args = beforeArr[l].advice.apply(this, args) || args;
}
// target method
var rs = dispatcher.method.apply(this, args);
// after methods
var afterArr = dispatcher.after;
for(var i = 0, ii = afterArr.length; i < ii; i++){
rs = afterArr[i].advice.call(this, rs, args) || rs;
}
// return object
return rs;
}
dispatcher.before = [];
dispatcher.after = [];
if( exist ){
dispatcher.method = exist;
}
dispatcher.target = target;
}
var aspectArr = (dispatcher || exist)[type];
var obj = {
advice : advice,
_index : aspectArr.length,
remove : function(){
aspectArr.splice(this._index, 1);
}
};
aspectArr.push(obj);
return obj;
};
}
window.aspect = {
before : aspect("before"),
after : aspect("after")
};
return window.aspect;
})(window, undefined);
以下是測試代碼:
var as = window.aspect;
var obj = {
url:"",
get : function(key){
return this["key"];
},
set : function(key, value){
this["key"] = value;
}
};
var h1 = as.before(obj, "set", function(key, value){
// 返回一個數組可以修改參數
value += " before-1 ";
//console.log(value);
return [key, value];
});
var h2 = as.before(obj, "set", function(key, value){
// 沒有傳回值則參數不會變化
value += " before-2 ";
//console.log(value);
});
obj.set("url", "http://mojijs.com");
console.log( obj.get("url") );
var h3 = as.after(obj, "get", function(value){
// 沒有傳回值不會修改原函數的傳回值
value += " after-1 ";
//console.log(value);
});
var h4 = as.after(obj, "get", function(value){
// 有傳回值會修改原函數的傳回值
value += " after-2 ";
//console.log(value);
return value;
});
console.log( obj.get("url") );
h1.remove(); // 刪除切面方法
h4.remove(); // 刪除切面方法
obj.set("url", "http://baidu.com");
console.log( obj.get("url") );