JavaScript

“this” keyword in JavaScript

An explanation of the “this” keyword in JavaScript

Moon
Moon
Dec 9, 2019 · 6 min read
Photo by Zachary Keimig on Unsplash

The “this” keyword is what we use every day in JavaScript. It’s widely used in every place in the project. But have you been using “this” on the strong understanding? You should be aware of the features of “this” to avoid potential side effects. In this post, I will introduce the features of “this” in JavaScript.

Before Reading

If you don’t know about JavaScript’s execution context, I recommend you read my previous post about Execution Context and Lexical Environment to get the basic knowledge of them. Then you can understand “this” keyword more easily.

What is “this”?

First of all, you should know what “this” is and what it does in JavaScript. There is an area called “execution context” in JavaScript, which is created either JavaScript runs the codes for the first time or a function is invoked. If 5 functions are called in a row, then there will be 6 execution contexts created — Global execution context, and other 5 function execution contexts. Each execution context contains a value called ThisBinding that is about “this” keyword.

So then what is it about? In JavaScript, “this” is a special keyword that allows you to access a certain object directly in the current scope, no matter where your current function is. By default, it refers to the global object. In Node.Js, it’ll be global and in Browser, it’ll be window .

But more important to remember is that what “this” points out is determined by which context calls a function that contains “this”. I will show you some examples in a second.

How to use “this” in a function

Take a look at the simple example of how to use “this” in JavaScript.

There are 2 possible cases for calling “this” in a function. obj.foo is referencing the address of foo . foo was called by obj and window . Even though there isn’t window. While obj.foo printed 2 out, window.foo printed 1 out. That’s because “this” is determined by which context calls the function.

When foo is called by obj , then ThisBinding of the execution context of foo refers to obj as its thisArg. In other words, “this” of foo called by obj is referring to obj . So when this.x is executed, “this” looks for x in obj . However, foo() is equal to window.foo() , so window becomes the object “this” refers to.

In the global scope, “this” is window .

// In the global execution context (scope)
this === window // true

The tricky part of “this”

Even though “this” is determined by the context which calls the function, “this” doesn’t always follow this rule.

Image source is from GIPHY

In the example, the console.log in the function bar prints 2 out, which is a global variable. Even though bar is declared inside the foo and bar is invoked within the execution context of foo , which sounds like bar also should print out 1, its “this” points to window . Why does this happen?

Sadly, it’s a flaw of JavaScript in its architectural level. Every inner function’s “this” points out window — it could be a method of an object, a callback function of some functions, or a normal function on the context. It doesn’t matter. Their “this” is always facing to window .

How to avoid this flaw?

There are several ways to avoid this, fortunately.

Function.prototype.bind

bind creates a new function, taking a parameter for “this”. Whatever you pass into the bind function, it’ll be the “this” of the function. It takes any type of value.

bind takes any value for thisArg

For example, if you pass {x: 10} to the bind as the first parameter, bind binds {x: 10} to the original function’s “this” and returns it.

Then how to use this?

Note this part.

bar.bind(this)();

Since bind takes the current “this” of foo as the parameter that it’ll bind to its “this”, so the new function from bar has “this” pointing out foo ’s “this”. Then you should run that function again to execute the codes inside.

Function.prototype.call and Function.prototype.apply

call and apply are similar to bind , but they execute the function, instead of making and returning a new function. Both consider the first parameter thisArg that “this” will refer to.

All you need to do is to write this.

bar.call(this);
bar.apply(this);

Note that unlike bar.bind(this)() , you don’t have to execute it once again.

call and apply are very similar to each other too, but there’s a slight difference. apply takes an array that contains all of the parameters, call , on the other hand, takes each parameter separately.

theFunction.apply(valueForThis, arrayOfArgs)theFunction.call(valueForThis, arg1, arg2, ...)

In this stackoverkflow question, there’s a really good comment of this.

Think of a in apply for array of args and c in call for columns of args.

Scope Chain

This might be an old way to avoid this problem but this is still loved by many developers since it’s very easy.

You can let any inner functions grab the variable declared in the outer function that holds “this”, like the example below.

This way is handy and useful, but the disadvantage is that you should declare a new variable that and the inner functions should always carry that.

An arrow function

Since ECMAScript 2015, a new feature of function was released. An arrow function can also avoid this problem.

The reason why it worked is that an arrow function’s ThisBinding points out the LexicalEnvironment of its outer execution environment, in other words, bar uses foo ‘s “this” when it calls “this”.

An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules.

So in this case, an arrow function won’t work the way you expected.

“this” in a constructor function

In JavaScript, any function can be used as a constructor function. But the convention recommended is to use the capital letter for the first letter, which is called “Pascal Case”. In a constructor function, “this” keyword works slightly differently.

When a constructor is called with the new keyword, a new prototypal function object is created. Internally, a new object({}) is generated for the return value and “this” is bound to that object that will be used by the new object — In this case, it’s person .

So this.name in Person is set by John when Person is called. John is assigned to the new object and it would look like this below.

function Person() {
var this = {};
this.name = 'John';
return this;
}

So the first console prints John . And we added a function, sayName , to its prototype, not to the function itself. “this” in a function bound to the prototype will automatically refer to the newly created object by the JavaScript engine. But, remember this won’t work as expected.

var name = 'Jane'; // Global variable...
Person.prototype.sayName = () => {
console.log(this.name);
};
var person = new Person();
person.sayName(); // Jane

Why does this happen? Because an arrow function doesn’t care which context calls it. Furthermore, it doesn’t have its own “this”, so when “this” is called within an arrow function, JavaScript starts to look for “this” as Scope Chaining. “this” in the global context is window , therefore, this.name in sayName, the arrow function, is equal to window.name , which is Jane .

Conclusion

“this” keyword in JavaScript is widely used by many developers and it is actually very convenient to use. But “this” isn’t a JS hack so you should be aware of the concept of it correctly. I hope that you keep it in your mind that “this” is easily changeable depending on how you use it.

Resources

JavaScript in Plain English

Learn the web's most important programming language.

Moon

Written by

Moon

Front End Web Developer in S.Korea. Interested in writing about Programmings. All of the posts could be written in English and Korean, which is my mother tongue

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade