JavaScript: Understanding ‘this’

The ‘this’ keyword in JavaScript can be a bit slippery. If you are coming from aclassical language like C++ or Java you might be surprised by how it behaves inJavaScript.

JavaScript uses late binding – meaning that ‘this’ isn’t evaluated until execution time.Here is the main thing to remember: what ‘this’ is a reference to depends on how a function is invoked. There are four ways to invoke a function in JavaScript: Function,Method, Constructor, and Apply.

Function When you create a plain old function that is not a part of an object ‘this’refers to the global object. That’s not something you would probably do intentionally, but, as we’ll see, JavaScript makes it easy to do this unintentionally.

function add(x, y) {
// 'this' refers to the global object
var sum = this.x + this.y;
// most likely NaN
return sum;
}

Method As a property of an object ‘this’ refers to the object it belongs to… usually (see caveats below)

var person = {
name: "Chris",
sayHello: function() {
// refers to the person object
return this.name;
}
}
person.sayHello();

Constructor When the ‘new’ keyword is used on a function that function becomes a constructor. Inside a constructor function the ‘this’ keyword again refers to the object. However, if the new keyword is omitted then the function will no longer be executed as a constructor function, and ‘this’ will refer to the global object.

function SpaceShip(name) {
this.name = name;
// it depends
return this;
// implied
}
// refers to the new object, this.name will equal "Millennium Falcon"
var transport = new SpaceShip("Millennium Falcon");
// refers to the global object, this.name will be undefined
var transport = SpaceShip("Millennium Falcon");

Apply When using the apply (or call) method the invocation object is passed in. This is useful if you want to call a method of one object on another object. In this case the’this’ keyword refers to whatever was passed in (or the global object if null).

var person = {
name: "Chris",
sayHello: function() {
// refers to the invoking object
return this.name;
}
}
var zombie = { name: "Fred" }
// refers to zombie, this.name will be "Fred"
person.sayHello.apply(zombie, params);

Caveats As we saw above accidentally calling a constructor function without the new keyword will cause ‘this’ to reference the global object. It can also be easy to loose track of ‘this’ when passing a function as a callback inside an object method.

// bad
var robot = {
model: "X47a",
report: function() {
doAjax('some_url', function(status) {
// oops! 'this' refers to the global object here
console.log(this.model + " " + status);
});
}
}

To keep ‘this’ bound to the parent object and not the global object we can either save a reference to ‘this’ in a variable.

// good
var robot = {
model: "X47b",
report: function() {
var that = this;
doAjax('some_url', function(status) {
// 'that' refers to a stored reference to the robot object
console.log(that.model + " " + status);
});
}
}

Or, in modern javascript environments, we can use the bind method.

// good
var robot = {
model: "X47c",
report: function() {
doAjax('some_url', (function(status) {
// 'this' is bound to the robot object
console.log(this.model + " " + status); }).bind(this));
}
}