Confusion about Function.prototype.bind()

I’m a huge fan of ES5’s Function.prototype.bind and currying arguments (basically creating default arguments for functions).

I was fooling around with that a bit, but I can’t for the life of me figure out my own construct anymore. This is my playground:

  • Difference between bind and on in backbone
  • Can binding out-of scope variables speed up your code?
  • Javascript's Bind implementation?
  • PHP equivalent of JavaScript bind
  • jquery disable click until animation is fully complete
  • How to avoid bind(this) on every function?
  • function hello( arg1, arg2 ) {
        console.log('hello()');
        console.log('"this" is: ', this);
        console.log('arguments: ', arguments);
    }
    
    var foo = Function.prototype.call.bind( hello,{what: 'dafuq'}, 2 );
    foo( 42 );
    

    The log output for this is as follows:

    hello()
    "this" is: Object{ what="dafuq" }
    arguments: [2,42]
    

    But I don’t understand how on earth the {what: 'dafuq'} object makes its way as a reference for the this within foo. As far as I understand it, we are creating a bound call to Function.prototype.call. Lets check the MDN synopsis for .bind() quickly:

    fun.bind(thisArg[, arg1[, arg2[, ...]]])
    

    so, thisArg for .call is the hello function, followed by the arguments list. Basically what happens is this

    Function.prototype.call.call( hello, {what: 'dafuq'}, 2);
    

    …uuhhh now my brain hurts a little. I think I have an idea now what happens, but please someone find nice solid words to explain it in detail.

    • how {what: 'dafuq'} becomes the this reference

  • Why won't my jQuery trigger work?
  • Remove focus programmatically?
  • How does function.apply.bind work in the following code?
  • Jquery binding number inputs doesn't work when increasing powers of ten (1000, 10000, 100000, etc.)
  • In JavaScript, the first bind determines who “this” is? (Binding it twice or a second time doesn't matter)
  • jQuery off() is not unbinding events when using bind
  • 3 Solutions collect form web for “Confusion about Function.prototype.bind()”

    But I don’t understand how on earth the {what: 'dafuq'} object makes its way as a reference for the this within foo

    It’s because foo is effectively the call method with the hello function bound as the calling context, and that object bound as the first argument. The first argument of .call sets the calling context of its calling context. Since you’ve bound it, it means that object always be the calling context.


    Put it this way…

    You’ve bound the calling context of .call to hello.

    This is effectively the same as doing…

       hello.call();
    // or...
    // Function.prototype.call.call(hello);
    

    You’ve also bound the first argument of .call to {what: "dafuq"}, so this is effectively the same as doing…

    hello.call({what: "dafuq"});
    // or...
    // Function.prototype.call.call(hello, {what: "dafuq"});
    

    And finally, you’ve bound the second argument of .call to 2, so this is effectively the same as doing…

    hello.call({what: "dafuq"}, 2);
    // or...
    // Function.prototype.call.call(hello, {what: "dafuq"}, 2);
    

    You’re not calling .bind(thisArg, args), but
    Function.prototype.bind.call(thisArgUsedByCall, thisArgUsedByBind, argument).

    A different way to show what happens:

    // thisArgUsedByCall is a function
    Function.prototype.call(thisArgUsedByCall, ...)   // does the same as:
    thisArgUsedByCall.bind(thisArgUsedByBind, argument);
    

    The short answer is that bind consumes the first argument and uses it as this, but then call consumes its first argument (which was bind’s second argument).

    Bind works like this:

    fun.bind(thisArg, argArgs...)(x, y, ...)
    

    becomes

    fun(argArgs..., x, y, ....) // this = thisArg
    

    So

    foo( 42 )
    

    is

    Function.prototype.call.bind( hello, { what: 'dafuq' }, 2 ) ( 42 )
    

    which becomes

    Function.prototype.call({ what: 'dafuq' }, 2, 42) // this = hello
    

    Call works like this:

    fun.call(thisArg, argArgs)
    

    Becomes

    fun(argArgs) // this = thisArg
    

    so

    call({ what: 'dafuq' }, 2, 42) // this = hello
    

    becomes

    hello(2, 42) // this = { what: 'dafuq' }