JavaScript ‘this’ keyword: A beginner’s approach

Anthony Oyathelemhi
5 min readJun 15, 2018

--

Photo by Pankaj Patel on Unsplash

The JavaScript this keyword is one of the properties that is passed to every function by default. Its value depends on the object that the function was called on and it is mostly implicitly defined by the JavaScript runtime but its behavior is not as direct as you would think. I am going to try to explain how to determine the value of this when used in functions.

Examine the code below for a moment, what do you think the output will be? Run it in your browser console to see the result.

let myObject = {
name: "Peter",
age: 20,
aboutMe: function(){
return "My name is "+this.name+", I am "+this.age + " years old"
}
}
console.log(myObject.aboutMe());

As you would’ve noticed, the code will print the following in the console

My name is Peter, I am 20 years old

We used this to reference the object that the function is contained in (myObject). Seems quite straightforward right? Now observe this

let myObject2 = {
name: "Prisca",
age: 24,
aboutMe: function(){
return "My name is "+this.name+", I am "+this.age + " years old"
},
child: {
name: "Sonia",
age: 2,
aboutMe: function(){
return "My name is "+this.name+", I am "+this.age + " years old"
}
}
};
console.log(myObject2.aboutMe());
console.log(myObject2.child.aboutMe());

Unsurprisingly, the second command prints the details of the child on the console, not the parent. So we can safely say that the this keyword implicitly refers to the nearest containing object. But what if the function is defined in the global scope?

The Global Object

Any binding or function not defined inside an object is attached to the global object, which is the Window object in the browser. You can test this by typing this; in the browser console and press enter. This will return the Window object with properties and values like you would expect of a regular object. You can even modify the properties of the Window object. Paste the following into the console

console.log(this.color); //Undefined
this.color = "Green";
console.log(this.color); //Green

The first line returns undefined because the Window object doesn’t have any property named color. The second line creates the property color and assigns it a value of "Green". And you can see that this property can now be accessed in the third statement. It is important to point out that the Window object is different across browser tabs, so the newly created property will not exist outside that tab.

Explicit ‘this’ declaration

Up until now, we have depended on the JavaScript runtime to help us determine what the value of this should be. While this is fine in some cases, it yields undesirable results in other cases. Take this asynchronous function for instance, what do you think the output will be? Try this in the console.

let myObject3 = {
firstName: "Michael",
age: 20,
aboutMe: function(){
setTimeout(function(){
console.log(this.firstName + " is " + this.age + " years old")
},5000)
}
}
myObject3.aboutMe();

The aboutMe method has a function that only executes after 5 seconds, so when it gets called, it ‘saves’ the function for later. When it eventually executes, it does so in the global scope and as such will return

undefined is undefined years old.

The reason this happened is simply because the keyword this at the time of execution refers to the Window object, not myObject3 and since none of those properties exist within the Window object, it returns undefined. So how do we solve this problem? We have to somehow tell the Async function what the keyword this is at any time of execution. JavaScript provides 3 ways to do this explicitly, call, apply and bind.

The Call Method

The same way objects have predefined properties (prototypes) like toString, functions have predefined methods too. One of those methods is call. The call method has many applications and use cases but ultimately solves one problem, which is setting the value of this within the function it is called on.

Let take two separate objects for example, similar to the ones we used before

let user1 = {
name: "Tony",
sayHi: function(){
return this.name + " says Hi"
}
}
let user2 = {
name: "Martha",
sayHi: function(){
return this.name + " says Hi"
}
}
console.log(user1.sayHi()); //Tony says Hi
console.log(user2.sayHi()); //Martha says Hi

Both objects have the exact same function sayHi, which is unnecessary duplication of code. We can write this function once and use it in the second object by using the function’s call method to determine the value of this.

let user1 = {
name: "Tony",
sayHi: function(){
return this.name + " says Hi"
}
}
let user2 = {
name: "Martha"
}
console.log(user1.sayHi()); //Tony says Hi
console.log(user1.sayHi.call(user2)); //Martha says Hi

Here we used the user1 function sayHi and used it’s call method to determine the value of this by passing in the argument user2. If the function had parameters, we can include the arguments in the call method

let user1 = {
name: "Tony",
greet: function(msg, friend){
return this.name + " says " +msg+ " to "+friend
}
}
let user2 = {
name: "Martha"
}
console.log(user1.greet("Hi", "James"));
//Tony says Hi to James
console.log(user1.greet.call(user2, "Hello", "Habeeb"));
//Martha says Hello to Habeeb

The Apply Method

Similar to the call method, the apply method does the exact same thing with one exception, it only accepts one argument. If the function has more than one parameters, we must pass the arguments as an array.

console.log(user1.greet.apply(user2, ["Hello", "Habeeb"]));

Both call and apply executes the function they are called on immediately. This poses another problem when we want to use them in an Asynchronous function call like the setTimeout function we used before.

The Bind Method

Unlike call and apply, bind returns the function it was called on but doesn’t execute it right away.

let myObject4 = {
firstName: "Michael",
age: 20,
aboutMe: function(){
setTimeout(function(){
console.log(this.firstName + " is " + this.age + " years old")
}.bind(myObject4),5000)
}
}
myObject4.aboutMe(); //Michael is 20 years old

This time, the correct message is displayed as intended. The bind method just attaches the correct object reference to the this keyword

So far we have seen 3 ways of explicitly setting the value of this. There is a fourth way of doing the same thing, the new keyword, but it is a bit beyond the scope of this article.

--

--