After having carefully read through every post/comment, I think the OP is
looking for [javascript]
and [method-modification]
. And answering right
away the OP's question about terminology, altering closed functionality in
JavaScript has nothing to do with Aspect-oriented Programming unless an
implementation that claims to be AO provides abstraction and code-reuse
levels for at least Aspect, Advice and Pointcut.
As it already has been commented
by Scott Sauyet, everything
else can be done by just (manually) wrapping functionality into one another. Here
again, I wouldn't go that far and calling it function-composition. In order to
qualify for that, there should be at least some tool-sets for it, as they already
exist with various implementations of compose
and/or curry
methods/patterns.
For what the OP is going to achieve there are a whole bunch of before
, after
around
/ wrap
solutions, mostly unfortunately mentioning AO(P), and in too
many cases not taking care of the context or target
which is essential and
also has been ask for by the OP.
The example I do provide uses a prototypal implementation of Function.around
.
Because JavaScript already features a standardized bind
, I'm firmly convinced
that Function.prototype
is the right place as well for some other method-modifiers
like before
,
after
,
around
,
afterThrowing
and afterFinally
.
code base that will support the afterwards following example:
(function (Function) {
var
isFunction = function (type) {
return (
(typeof type == "function")
&& (typeof type.call == "function")
&& (typeof type.apply == "function")
);
},
getSanitizedTarget = function (target) {
return ((target != null) && target) || null;
}
;
Function.prototype.around = function (handler, target) { // [around]
target = getSanitizedTarget(target);
var proceed = this;
return (isFunction(handler) && isFunction(proceed) && function () {
return handler.call(target, proceed, handler, arguments);
}) || proceed;
};
}(Function));
example code, altering a given closed function by additionally provided behavior before and after it and also providing it's context.
var loggingDelegate = function () { // closed code that can not be changed for any reason.
this.log.apply(this, arguments);
};
loggingDelegate.call(console, "log", "some", "arguments");
var interceptedLoggingDelegate = loggingDelegate.around(function (proceed, interceptor, args) {
// everything that needs to be done before proceeding with the intercepted functionality.
// [this] in this example refers to [console], the second argument of the [around] modifier.
this.log("proceed:", proceed); // the original functionality - here [loggingDelegate].
this.log("interceptor:", interceptor); // the modifying functionality - [around]s 1st argument.
this.log("args:", args); // the arguments that get passed around.
proceed.apply(this, args);
// or:
//return proceed.apply(this, args);
// or:
//var result = proceed.apply(this, args);
// everything that still needs to be done after invoking the intercepted functionality.
// if necessary:
//return result;
}, console); // [console] has to be provided as target to the modified [loggingDelegate].
interceptedLoggingDelegate("intercept", "and", "log", "some", "arguments");