Based on dotvoid solution, I created my own version of JS AOP for my own projects needs.
I basically want to minimize the aspect setup costs, so I added aspect setup functionality at
Function.prototype.
Function.prototype.applyBefore = function (aspect, targetFuncNames) {
....
}
I also need to support aync callbacks, such as supporting authentication and authorization for certain methods.
For example:
var authenticateAspect = function (error, success, context, args) {
logger.log('authenticate (applyBefore async) aspect is being called');
var request = $.ajax({
url: "http://localhost/BlogWeb/api/user/authenticate",
type: "GET",
data: { username:'jeff', pwd:'jeff' },
success: function (data) {
if (data) {
success();
} else {
error();
}
},
error: error
});
return request;
};
Person.applyBefore(authenticateAspect, 'sendNotification');
var p1 = new Person();
p1.sendNotification();
To implement this, I need to run the security and and continue upon success or stop execution on failure.
var invalidAspect = new Error("Missing a valid aspect. Aspect is not a function."),
invalidMethod = new Error("Missing valid method to apply aspect on.");
///Parameters: aspect - defines the methods we want call before or/and
/// after each method call ob target obejct
/// targetFuncNames - target function names to apply aspects
///Return: it should return a new object with all aspects setup on target object
Function.prototype.applyBefore = function (aspect, targetFuncNames) {
if (typeof (aspect) != 'function')
throw invalidAspect;
if (typeof (targetFuncNames) != 'object')
targetFuncNames = Array(targetFuncNames);
var targetObj = this;
//error handling function
// Copy the properties over onto the new prototype
for (var i = 0, len = targetFuncNames.length; i < len; i++) {
var funcName = targetFuncNames[i];
var targetFunc = targetObj.prototype[funcName];
if (!targetFunc)
throw invalidMethod;
targetObj.prototype[funcName] = function () {
var self = this, args = arguments;
var success = function() {
return targetFunc.apply(self, args);
};
var error = function () {
logger.log('applyBefore aspect failed to pass');
//log the error and throw new error
throw new Error('applyBefore aspect failed to pass');
};
var aspectResult = aspect.apply(null, Array.prototype.concat([error, success, self], args));
return aspectResult;
};
}
};
Full implementation can be found at http://www.jeffjin.net/aop-with-javascript