‘this’ is always been a pain in the a** for many JavaScript developers, but it’s time to say ‘I got this’
Previously, I wrote Understanding Scope and Context in JavaScript. Before reading this article, I recommend you read that article first, but if you think you have a good grasp on scope and context in JavaScript let’s continue.
So What is 'this’ in JavaScript?
The value of
this keyword in a global context refers to a global object which is Window in case of browser.So answer to "what is
this in JavaScript" is simple. this contains a value that is most of the time is an object which is an execution context at that particular time.As you can see in the above example, by default,
this will contain an object the value that refers to the global execution context which is Window in web browsers.The value of
this is determined by how a function is being called.if a function is called with a new keyword JavaScript will create a separate execution context for it.
Note: The value of this will change if we run it in strict mode.
As you can see in the above example, if
constructorFunction called normally, this will now contain undefined value since it is running in strict mode.JavaScript has introduced a new property called
globalThis which points to global this value.Note: The value of global this is different in NodeJS (Object), and in WebWorker it might be DedicatedWorkerGlobalScope or SharedWorkerGlobalScope but in a web browser, it will be Window.
So all in all, this is nothing but the execution context in which that particular line of code is running, which is defined at runtime bindings
And as you can see, almost in all scenarios this is nothing but an object,
we sometimes call it context or execution context
we sometimes call it context or execution context
How the value of 'this' is determined
We have understood what is
this and what it contains, it’s time to learn some rules which identify the value of this at any given point in time.Determining the value of
this is the HARD part for many, which makes this controversial in JavaScript.We’ll list down all possible scenarios where
this value gets changed.Default value
This is the most simple part, open up devtools and log
this , it will look like this in Chrome.As you can see, all are logging the same value which is a Window object.
This is the default execution context in JavaScript, every function by default gets executed in the default context.
A variable declared in the global scope (using var) gets added in the
Window object and we can access them using window.varNameChanging the value of this
If this will always point to the Window object, we can not achieve code reusability, code abstraction and we will pollute the global context.
That's why there is a way using which we can create custom context and change the execution context of some function that is already defined in some other context.
That's why there is a way using which we can create custom context and change the execution context of some function that is already defined in some other context.
Call, apply, and bind to rescue us.
These are the methods available on the Function prototype, and the purpose of all three methods is the same it’s just that there is deference in implementation.
We are not going to look at these methods in detail but will explain in short with some examples.
Let’s imagine, you wrote a function called
printName that accepts messages as input and prints a variable called name to the console from the context in which it is running.All good, right, In the above example, we created a variable called name which will get added on the window object, and since
printName function by default runs in global context variable name is available on this.Now imagine, there is a change in requirements and now you have another object called user who also contains a property called name and you want to print it on the console.
Since you are a good programmer and you practice DRY, you want to reuse the above function which does the job.
As you can see above, we are now able to print property called
name which is available in user object and not in the Window object.Basically, we are changing the context of the original
printName function which by default runs in the global context.And
call, apply and bind method saying, printName please run-in user context,Have a close look at the below example, Now we are also logging
this in printName functionAs you can see, when we call
and when we call using call, apply, and bind this is pointing to the User object.
printName Normally this points to Windowand when we call using call, apply, and bind this is pointing to the User object.
Normal function vs arrow(fat) function
As you can see in the above example, we created an object called
customeScope and defined an anonymous function and assigned it to a property called printName which prints this and name property. The second example is identical to the first only difference is that we are using the arrow function.But this small difference results in a big change.
Explanation:
arrow(=>) function by default does not have this set to Window which is in normal function. Rather an arrow function executes in scope they are created.
In the above snippet, in the first example, this is pointing to a context in which they are created which is customeScope.
In the second example, since the arrow function do not have it’s own
this, it will use this value of enclosing scope, which is Window (enclosing scope is customeScope whose this is Window).Arrow function example
That's all for today, I have tried my best to explain what is
this and how it may get changed in various scenarios.Hope you have learned something new today…
For further understanding please consider the below sources:
Feedback and suggestions are welcome.
Reach out to me on Twitter.
Until then...