jcubic
jcubic

Reputation: 66590

Can Function.prototype.call be overloaded to log all function calls?

I've try to change Function.prototype.call to console.log all functions calls (for debugging), but my browser crashed, is it possible? If yes how the code should look like?

I've try to do something like this:

(function(call) {
  Function.prototype.call = function() {
    console.log(this);
    call.apply(this, arguments);
  };
})(Function.prototype.call);

but got lots of toString() { [Native code] } when I move the mouse over the page, and I needed to kill that tab were I call that code.

Upvotes: 1

Views: 241

Answers (2)

Moritz Roessler
Moritz Roessler

Reputation: 8641

tldr; No, it's not possible to intercept every function call by some sort of universal getter.

Function.prototype.call is not called each time you call a function, but is used to pass another thisArg when calling a function, meaning it's not implicitly called when invoking a function.


The nearest you could get would be iterating over all globally accessible functions or an array of references to functions you're interested in, and patching each and every one.

However, this also implies that you can only intercept those functions, you already know about. If a function is not globally accessible, e.g. contained in a Lexical Environment, hidden from your code, or was declared after your function ran, you won't catch it.

So while you can override a single function, or define a getter for it, it's unfortunately not possible to generally intercept every function call.

If you, however want to catch all functions called via Function.prototype.call you can indeed override it.

There are 2 things you would need to change, in order for this to work.

  1. Since you pass an object (this) to console.log, Object.prototype.toString gets called with that object as thisArg. And you end up in an infinite loop.
  2. You don't return the result of the call to the original Function.prototype.call call. Which breaks code that relies on this return value.

Given this, a slightly modified version should log the names of the functions, call is being invoked on.

(function(call) {
  Function.prototype.call = function() {
    console.log(this.toString ());
    return call.apply(this, arguments);
  };
})(Function.prototype.call);

However. It seems you want to catch any function, called. This won't be possible this way, only functions, invoked using Function.prototype.call can be intercepted.

Upvotes: 2

Jeremy J Starcher
Jeremy J Starcher

Reputation: 23863

I have found that I've crashed more than one browser with excessive logging... that sounds like a recipe for disaster.

In addition, most (all?) modern browsers make that property read-only to keep a 3rd party script from spying on what is happening on the system.

Your best bet is to use the profiling tools in FireFox or Chrome to track what is happening.

Upvotes: 1

Related Questions