What is JavaScript “this”?
this
is a JavaScript keyword which is vastly misunderstood by a lot of developers and this post aims to bridge that gap. While this article is written for beginners but even experienced developers can use it as a refresher. this
is a special identifier keyword which is automatically defined in the scope of every function but what it actually refers to is the real deal. This post is divided into three parts and in the first part, we will talk about what this
is and then we’ll talk about some common misconceptions about this
and finally, we will see some features of JS related to this
keyword.
Prerequisite
I believe learning is like working out and if you don’t warm yourself up properly then you might end up hurting yourself. Thus before talking about this
, let’s talk about a few JavaScript concepts which you should be familiar with for this article.
1) The variables declared in the global scope as var a = 2;
are nothing but global-object properties of the same name. Yes, they are not copies of each other but are each other. To make this clearer look at the example below how we are able to access the value of x
as the key of the global object window
. Further, a thing to must note here is this only works with declarations using var
, not let/const
.
2) Call-site: The location where a function is called from is called call-site. Usually finding the call-site just comprises of locating the line where the function is called from but this can be misleading as a function can be called at multiple places in the code. Thus the most accurate way to find the call-site is to find the call-stack and then see where the function was called from or in other words what was the previous function in call-stack. Let’s understand this with an example.
What is this
?
this
is a binding made for each function invocation whose value depends on how and where the function is called. Binding made for this
is usually related to variables declared using var
and JavaScript running in non-strict mode. Further on the basis of the call-site, we can divide such bindings into four parts as given below:
- Default Binding
- Implicit Binding
- Explicit Binding
- new Binding
Default Binding: When we call a function in the global scope normally with no special decoration. this inside the function gets bound with the global scope. Yes, you can access all global variables using this inside such functions. One thing to notice here is it is only applicable for non-strict
mode and variables defined using var
.
Strict mode: The value of this
is undefined in this case.
let/const: The variables defined with let/const
are not bound.
Implicit Binding: When the call-site of function has a containing object (context object) as given below. That context object is bound to this inside that function. In the example below, obj
is the context object and this gets bound to this object and all the keys will be accessible inside the function using this.
Strict mode: This will work the same as non-strict
mode.
let/const: Not applicable
Explicit Binding: This binding gives us the superpower to assign this
to anything. We can achieve this using call(..)
and apply(..)
methods. Yes, we can set this
to an object, variable, function or anything. But there’s a catch, null
and undefined
are replaced with global object and primitives are converted into equivalent objects. Whatever we will pass as the first argument that will be used as this binding by the function call, sweet.
Strict mode: null
and undefined
don’t get replaced with the global object and primitives are not converted into objects.
let/const: Not supported when this
binds to the global object (either directly or after getting replaced from null
or undefined
) but variables defined with let/const
can be directly passed as this
and it will get bound.
New Binding: This one can feel a little odd from the rest of the binding rules. In this kind of binding, if we invoke the function with new
keyword and assign it to a variable then this
is bound to that variable. Look at the example below for understanding. Here we assign the value of new doSomething()
to bar
thus inside the function, this gets bound to bar
.
Strict mode: No effect
let/const: The variables defined can be both let/const
, the same behaviour is observed.
What this isn’t?
Let's see the most common misconceptions about this
which a lot of developers have and dive deeper into each of them. People think this
in a function refers to:
- Itself
- Its Scope
Itself Many developers believe that this refers to the function itself in which it is called which is wrong. Below is a simple example to prove it.
Rather the correct way to keep track of how many times increase
is called would be to actually use the call
method to explicitly define the this
keyword to be the increase
object (itself). The below-given code example is a working example of it.
Its Scope Another famous misconception developers have is that they think that it refers to the function’s scope. It is a tricky one because in global scope, this
refers to the global scope itself but it is quite a misguided statement as we saw that it is not true in the previous section.
More JavaScript Features around `this`
bind() function: ES5 introduced this function which helps bind the value of this
explicitly. bind
returns a function with this
set to the first argument of bind
. This is something similar to call
and apply
but the difference is once we use bind
the function retains its context so that it can be reused.
arrow function: In these functions, this
retains the value of the enclosing lexical context's this
. In global code, it will be set to the global object. Let's see a few examples below:
this
in classes: The behaviour of this
in classes and functions is the same since classes are nothings but functions under the hood. Still, I would suggest a read here that has a few corner cases. A common convention is to override this
behavior so that this
within classes always refers to the class instance. This is commonly seen in React Class components.
this
as a DOM handler: When a function is used as an event handler, its this
is set to the element on which the listener is placed. The code given below will print the DOM element itself.