This, apply, call, bind
No matter what Marcus says, THIS is hard as hell to understand.
Let’s try to figure it out.
Method is called by owning object
In a method, this refers to the object the method belongs to at time of execution.
If we have an object called eric, which has a method move(), it’d look like this:
var person = {
position: 0,
move: function() {
this.position++;
}
};
When we call the function move(), we’d do it like this:
person.move(); // position === 1
move() is called by person, and inside the move function, this references the person object. This is obvious enough just by looking to the left of the dot.
But there are twists!
Method is called by global object
Remember, inside a function, this belongs to the object that executes the function call.
Why is this confusing? Because sometimes a function isn’t immediately executed. Instead it’s passed to another function (e.g. setTimeout(person.sayHi, 1000)) to be executed at a later time. At the time the function setTimeout(person.sayHi, 1000) is executed, this is a reference to the object that executed sayHi(), even if sayHi was passed was a method of a separate object (person).
Let’s look. The object below contains the function sayHi. The function’s output includes a reference to the calling object’s name property.
var person = {
name: 'eric',
sayHi: function() {
console.log('Hi, my name is ' + this.name);
}
};
setTimeout(person.sayHi, 1000);
So in setTimeout(person.sayHi, 1000), what is the calling object?
setTimeout is a global function, which means its this is a reference to the window object. This means the window object is also the object which executes sayHi(), making the this in sayHi a reference to the window object!
setTimeout has the function definition as a parameter, and executes it at a later time. Why is the function definition important? Because all setTimeout has is the function description, and nothing else. A function description is not an execution of the function itself, and has no other special information besides the details of how to execute the function.
In a simpler example, if you pass (10 * 5) as a parameter to a function, the function receives 50, not the specifics of the parameter operation!
In fact, setTimeout has no idea who ‘person’ is, or that ‘person’ owns the function object. It simply has the function definition to execute at a later time.
Therefore, the object this references isn’t ‘person’. This references the object it’s called by.
Since setTimeout executes sayHi, and setTimeout is called by the global object, which is window, the window object is what this references.
When we call
setTimeout(person.sayHi, 1000);
this is a reference to the window object, which does not have a name property, so name is undefined. The output is then:
Hi, my name is
bind()
When we encounter situations where it’s possible to lose a this binding, it’s possible to permanently bind this using bind().
bind() is a method of all function objects, and receives a this reference as a parameter to bind the function to.
In the previous example, this referenced the window object.
setTimeout(person.sayHi, 1000); // Hi, my name is
If we want to keep reference to the person object, we can change the call to:
setTimeout(person.sayHi.bind(person), 1000); // Hi, my name is eric
Note, bind is similar to apply() and call() in that it forces a this reference, but unlike apply() and call() (see next session), it does not immediately execute the function.
apply() and call()
Along with bind(), every function object has an apply() method and a call() method. Similar to bind(), they force a this reference.
The difference is apply() and call() will execute the function immediately.
apply() and call() have essentially the same functionality, except if called on a function with parameters, apply() accepts an array of parameters and call() accepts a list of N parameters.
person.listAppendages.apply(person, ['arms', 'legs']);
person.listAppendages.call(person, 'arms', 'legs');
Important: we should not use apply() nor call() in the setTimeout function in the previous example. Recall that apply() and call() will execute a function immediately. So if used in the context of setTimeout, they would cause the parameter function to execute regardless of wait time.