The this
keyword in JavaScript has confused a lot of developers. Whether you are just starting your career in programming or you are an experienced
developer. It confuses everyone alike.
Now before starting let’s get into the fundamentals of how this
works in
javaScript. this
always refers to the calling context of a function inside an object, which will usually be the object with which the function is associated with. Now, Since we have so many libraries at our disposal in the javascript ecosystem we just grab a library and start building something without actually understanding what is going on. While you will be able to build amazing applications but when it comes to debugging those applications that’s when the understanding of the weird parts of the javaScript comes into the picture. Now, javaScript is still evolving even after so many years but the fundamentals of language will always remain the same.
this
does not refer to the function in which it is used, but always refers to the object in which it is executed. Let’s understand this by an example.
const obj={
myFunction: function(){
console.log(this===window)
}
}
obj.myFunction()
Now, in the above example, we expect this behavior because here this
will always refer to the calling context of a function which here is obj.
Now this behavior will be true in any other object-oriented language. This is the default assumption because this is how this
works in most other languages. Now, let’s change a few things and see how the behavior of this
changes.
Now, in this example object declaration is the same but here we assign it
another variable and the call it afterward instead of calling it right away. Now if we call the newVariable, suddenly the value of this
changes from obj
to the global
or window
. Now, this tends to trip up a lot of developers. Now in order to understand what value this
will hold we need to look where it is being called not where it is written. In the above example, it is being called in the global object and not the obj
object.
Let's look at some complex examples.
const obj={
myFunction: function(){
console.log(this===obj)
setTimeout(function(){
console.log(this===obj)
console.log(this===window)
})
}
}
obj.myFunction()
Now, this example is similar to the above example but here we use setTimeout which is an asynchronous task. Now, if we run this we get something different.
We see that inside setTimeout now the value of this again changes back to the window
or global
depending upon the environment i.e Nodejs or browser. Now even though it’s the same block of code the value of this
changes to window
. Now, going back to the first rule this
does not depend on where the function is being written but where it is called and in case of asynchronous calls a new async function
object on the window
object. Okay, now let’s take a look at the same example but written a little differently using an ES6 arrow function.
const obj={
myFunction: function(){
console.log(this===obj)
setTimeout(()=>{
console.log(this===obj)
console.log(this===window)
})
}
}
obj.myFunction()
Interestingly, Now the value of this
changes back to obj
instead of window
. An important thing to note is that this
always get binding happens in 3 ways- default binding, implicit binding, and explicit binding. Now whenever we define a standalone function execution, it is always a default binding and it always binds to window
object.
Now, we have to keep that default binding will always be our fallback binding.
Let’s get to know a little bit about Explicit and Implicit binding and understand how that works.
Implicit Binding
Now implicit binding happens whenever we have a function call and whatever is to the left side of the dot it is going to refer to that.
In this example, we have obj to the left side of the dot so it is going to refer to that i.e obj
.
<br>
Explicit Binding
Explicit binding of this
occurs when .call(),.apply(), or .bind() are used on a function.
We call these explicit because you are explicitly passing in a this
context to call() or apply(). Let’s take a look at how explicit binding looks like in the following example.
const obj={
myFunction: function(){
console.log(this===obj)
}
}
const newFunctionVariable=obj.myFunction
newFunctionVariable.apply(obj)
Now even though we are assigning myFunction
to a new variable we can still say to what this
context this function call will be bound to. We can see this by looking at another example where we can bind it to a completely different object below.
const obj1={
firstName:"Sachin",
lastName:"Thakur",
myName:function(){
console.log(this.firstName+" "+this.lastName)
}
}
const obj={
myFunction: function(){
console.log(this)
console.log(this==obj1)
}
}
const newFunctionVariable=obj.myFunction
newFunctionVariable.apply(obj1)
Now, in this, if we pass the first parameter as obj1
it will take the this
reference of obj1
even though the function is defined on obj
. And this is how the Explicit binding works.
Now with the introduction of ES5 arrow function, the javaScript engine
introduced a new behavior. Before arrow functions, every new function defined its own this
value based on how the function was called:
- A new object in the case of a direct function call with
window
context asthis
(Default Binding) undefined
in strict mode function calls.- The base object if the function was called as an “object method”.(Implicit Binding)
- You could also Explicitly define what
this
will refer to like we saw in the last example. (Explicit Binding)
An arrow function does not have it’s own this
. The this
value comes from the lexical scope. Arrow function follows the normal variable look rule. If the value is not found in its scope go one level up and find the value in the enclosing scope. That’s why we don’t need to bind this
value to the object explicitly as long as it is available in it’s enclosing scope.
Thus, in the following code, the this
within the function that is passed to setTimeout
has the same value as the this
in the lexically enclosing
function:
<br>
const obj={
myFunction: function(){
console.log(this===obj)
setTimeout(()=>{
console.log(this===obj)
},0)
}
}
obj.myFunction()
Conclusion
this
can be a little tricky sometimes but if we know the basic fundamentals of how scoping words and how javaScript treats an object, we can easily understand how these core concepts work. this
can be a little tricky in case of callback or async function where the value of this
changes. Always remember this
value is assigned the value of the object where it is being invoked.