Search code examples
javascriptecmascript-5

Why does fn.call() fail after being assigned to a variable


Let's say we create a simple function

> function foo() { return 0; }

We could either call it directly

> foo();
> 0

Or we could call it using the Function.prototype.call() method

> foo.call({}); // Using empty object as this arg
> 0

So far so good. Now here is where things get strange. We can always assign a function to a variable in javascript, and call it under a new name

> var x = foo;
> x();
> 0

However, if we try the same thing with Function.prototype.call() we get an error

> var x = foo.call;
> x({});
> Uncaught TypeError: x is not a function

I imagine it has something to do with how the prototype chain works in javascript. Could someone explain to me the problem here?


Solution

  • When you grab the reference to the call function:

    var x = foo.call;
    

    It does not carry over the context. In order to get this to work, you need to bind the context to call:

    function foo() { return 0; }
    
    var x = foo.call.bind(foo);
    
    x(); //0
    

    This can also be accomplished by binding after the creation of x:

    function foo() { return 0; }
    
    var x = foo.call;
    
    x.bind(foo)(); //0