Search code examples
javascriptfunction-prototypesnative-methods

Invoke Function.prototype.apply inside a re-declaration of apply (Javascript)


While learning Javascript, I tried to re-declare the apply property of a function. Thus far no problem.

function foo() { return 1; }
alert(foo()); // 1
alert(foo.apply(null)); // 1
foo.apply = function () { return 2; }
alert(foo()); // 1
alert(foo.apply(null)); // 2

Now, I tried to make apply do something more and call the "old" apply (like logging).

var old = foo.apply;
foo.apply = function() {
   alert("A");
   return old(null);
}
alert(foo.apply(null));

I get

TypeError: Function.prototype.apply was called on [object Window], which is a object and not a function


I tried

foo.apply = function() {
   alert("A");
   return arguments.callee[Function.prototype.apply](null);
}
alert(foo.apply(null));

I get

TypeError: Property 'function apply() { [native code] }' of object function () { alert("A"); return arguments.calleeFunction.prototype.apply; } is not a function


Is there any real way to accomplice what I try? Or is it some restriction due to Function.prototype.apply being native code?


Solution

  • Yes. apply expects to be applyed (yes, with exactly itself) on a function, while the way you used it (by old()) makes its this value the global object (window). So you can do this:

    var old = foo.apply; // === Function.prototype.apply
    foo.apply = function() {
        // "this" is the function foo
        alert("A");
        return old.apply(this, arguments); // applying the (old) apply function on foo
        // or better without any arguments:
        return old.call(this); // like this(); which is foo()
    }
    alert(foo.apply(null));
    
    // and the call solution with an argument:
    foo.apply = function(context) {
        return old.call(this, context);
        // like this.call(context);
        // which is foo.call(context)
        // which is like context.foo()
    }
    

    Also check out the docs for the call and apply "methods" (though we've use old not as a method, but as a pure function).