So, I would like to have some code executed everytime a given function is called, is that doable? Thing is, I could just overwrite the existing function and add the code, but that would require me to know the exact content of that function... Imagine a "plug-in" to a "library", and you want the plug-in to execute code everytime a specific function of this librairy is called, but you don't want to overwrite the original librairy content... Hope I'm clear enough!
And if it is doable, is there a way to retrieve the arguments submitted to the function?
-
In aspect oriented and functional programming, what you're asking about is called "advice".outis– outis2010年10月28日 00:06:05 +00:00Commented Oct 28, 2010 at 0:06
4 Answers 4
Sounds like a job for a wrapper function to me.
Write a function that calls the other function, and put your code at the end of that (or wherever). Then always call your version instead.
Sort of an adapter pattern. http://en.wikipedia.org/wiki/Adapter_pattern
I believe you can hide the scope of the original function and name yours the same if you cannot modify calling code (doesn't work on some intrinsic functions like alert, but should work for library code). If that isn't an option, see if prototype will let you extend the object to add the functionality. http://phrogz.net/js/classes/ExtendingJavaScriptObjectsAndClasses.html
//Only add this implementation if one does not already exist.
if (Array.prototype.slice==null) Array.prototype.slice=function(start,end){
if (start<0) start=this.length+start; //'this' refers to the object to which the prototype is applied
if (end==null) end=this.length;
else if (end<0) end=this.length+end;
var newArray=[];
for (var ct=0,i=start;i<end;i++) newArray[ct++]=this[i];
return newArray;
}
For arguments, you can also make your version take optional arguments (similar to jQuery / MooTools) and then look at what was passed.
Examples of optional arguments here. http://www.openjs.com/articles/optional_function_arguments.php
function accident() {
for( var i = 0; i < arguments.length; i++ ) {
alert("This accident was caused by " + arguments[i]);
}
}
2 Comments
It's definitely doable. JS is a dynamic language, so you can swap a function stored in an object with your own. For example:
var fxnToWrap = obj.someFunction;
obj.someFunction = function() {
console.log("booyah, I'm intercepting every call to obj.someFunction");
fxnToWrap.apply(obj, arguments);
}
2 Comments
Possibly you could overwrite the reference to the function? For example:
function add1(x) { return x + 1; }
function log_calls(f, name) {
return function() {
console.log("got a call to", name, "with args", arguments);
return f.apply(null, arguments);
}
}
add1 = log_calls(add1, "add1");
Then calls to add1 would be something like:
>> x = add1(42)
"got call to add1 with args [42]"
>> x
43
Comments
Edited to correct mistake pointed out in comment
This might solve your problem:
function f() {alert("in f");}
var saved_f = f;
var f = function() {
alert("in f2");
saved_f();
}
f();
2 Comments
saved_f will point to the last f defined function (causing infinite recursion). Function declarations are subject of hoisting. It can seem to work if you try it on the firebug's console, because Mozilla implementations define a Function statement, and the console evaluated code is wrapped in a with block. In fbug, try to wrap the above code in an anonymous function e.g. (function (){})();