javascriptfunctionbindingmethod-invocation

Javascript function invocation & binding


I have the following part of code:

var person = {
  name: "Brendan Eich",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

var bind = function(func, thisValue) {
  return function() {
    return func.apply(thisValue, arguments);
  }
}

var boundHello = bind(person.hello, person);
boundHello("world") // "Brendan Eich says hello world"

Here, the code will print out in the console the text

Brendan Eich says hello world

if I take the bind variable assignment and I change it to:

var person = {
  name: "Brendan Eich",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

var bind = function(func, thisValue) {
  return func.apply(thisValue, arguments);
}

var boundHello = bind(person.hello, person);
boundHello("world") // "Brendan Eich says hello world"

then the results is

Brendan Eich says hello function(thing) { console.log(this.name + " says hello " + thing); }

Could someone explain me why is that happening and what exactly are the 2 nested return functions inside the bind one?

How exactly do they work?


Solution

  • I will try to explain as best as I can. On the first example your bind definition is a function that get two arguments, ideally a function as first argument (lets call it THE_FUNC) and an object as second argument (lets call it THE_THIS_ARG) that will use as the thisArgs for that function.

    Now, this bind definition returns a function that explicitly takes no arguments (but implicitly could take any arguments) and when this function is called it will return the evaluation of calling apply on THE_FUNC using THE_THIS_ARG as the value of this for THE_FUNC and using the arguments received (lets call it THE_ARGS) as the arguments passed to THE_FUNC.

    For your particular example, the setup will be this one:

    THE_FUNC => person.hello

    THE_THIS_ARG => person

    THE_ARGS => ["world"] (array-like object)

    Finally boundHello("word") is then traduced in something like (not exactly) this:

    person.hello.apply(person, ["world"]);
    

    Maybe, next example with some debugs can help you to understand better than my explanation:

    var person = {
        name: "Brendan Eich",
        hello: function(thing)
        {
            console.log(this.name + " says hello " + thing);
        }
    }
    
    var bind = function(func, thisValue)
    {
        console.log("func is: ", func);
        console.log("thisValue is: ", thisValue);
        return function()
        {
            console.log("Arguments are:", arguments);
            return func.apply(thisValue, arguments);
        }
    }
    
    var boundHello = bind(person.hello, person);
    boundHello("world") // "Brendan Eich says hello world"

    The same explanation is some sort of valid for the second example too. But in this case bind do not return a function like in the previous example, and instead call apply with this setup:

    THE_FUNC => person.hello

    THE_THIS_ARG => person

    THE_ARGS => [person.hello, person] (array-like object)

    So, when you call bind(person.hello, person) is then traduced into something like:

    person.hello.apply(person, [person.hello, person]);
    

    And as you can see person.hello will be the thing argument received by person.hello() method and that is the reason a function definition is printed in the place of the thing argument.

    var person = {
        name: "Brendan Eich",
        hello: function(thing)
        {
            console.log(this.name + " says hello " + thing);
        }
    }
        
    var bind = function(func, thisValue)
    {
        console.log("Arguments are:", arguments);
        return func.apply(thisValue, arguments);
    }
    
    var boundHello = bind(person.hello, person);
    //boundHello("world") // "Uncaught TypeError: boundHello is not a function"