THIS
keyword in JavaScript is the most powerful mechanism but also the most misunderstood one too.
The common confussions about "this" keyword are-
this of a function, refers to the function itself. But it is not true. Unlike other programming languages, "this" does not refer to the function itself.
Another misconception is that- this points to the instance that a method belongs to. Again this is not true.
What is this keyword then?
If you are not very much familiar with the object-oriented paradigm of Javascript then you must be wondering -
What is the this
keyword in JavaScript? How does this
keyword work in JavaScript? What is the use of this
?
I will explain this
keyword in simple words-
"This" keyword is an object which is not tightly coupled with a function. A function uses
the value of "this" from its environment where it is executed. this
keyword is part of current context of the function(during execution)
which can be changed by binding the new context.
Now you must be wondering, what is execution context ?
Execution context is just an abstract concept. It is the environment in which the JavaScript code is executed. It holds information like the
value of "this", variables, objects, and functions.
Javascript engine decides the value of this
at execution time. Execution time means- Actual time when your code run.
May be while writing your code it points to this
but while execution this
is changed to that
.
It is because, all the bindings, references, and memory assignments are done at execution time.
Let's understand this keyword step by step.
In the global context, "this" refers to the window object. By default within a function, this is bound to window object. Check the below example.
cosole.log(this) //window object function test(){ cosole.log(this); } test() //window object
Check the below example 👇, this.title
print the global variable title. It is because, title is global variable and
thus becomes part of the window object.
And this
within function points to window
object.
var title = 'ui dev'; function printTitle() { console.log(this.title); } printTitle(); //ui dev
Remember: When the JavaScript engine starts executing the code, very first thing it does is creates a global execution context. The global execution context is initialised with the window object. At that point of time, "this" points to the window object.
console.log(window === this) //true function test(){ console.log(window === this); } test(); //true
Within a function, by default, this
refers to the Global object. But, If we use strict mode, this
is undefined within the
function. It is because, strict mode does not allow default binding.
"use strict"; function test(){ console.log(this); }; test(); //undefined
In an object method, this
refers to the "owner" of the method that is- object itself.
var student = { name: "John", age : 30, printDetail: function(){ console.log(this.name, ' ', this.age) } }; student.printDetail()// John 30
printDetail
is a method within the Student Object, this
used within that method refers to the "owner" of the method,
that is Student object.
In the below example, printThis
is a function that simply prints this
value that is window.
function printThis(){ console.log(this); //window object } var person = { firstName: "John", lastName : "Doe", print : printThis, }; person.print() //{firstName: "John", lastName: "Doe", print: Æ’} var printRef = person.print; printRef() // window object
If we directly call printThis()
function it will print the global window object.
But if we assign it to print of person object and execute the print method directly, person.print()
it will log the person object itself.
However, if we hold the reference of person.print
to another variable and execute it later, it will log the window object. This is because the
execution context is changed and now this
points to window object. We are not doing anything but the JS engine is doing implicit bindnig
work depends on the current execution context.
In the above example, person.print
is giving 2 different output because of the change of the execution context. When we
directly invoke person.print()
method, it runs within the context of the person object.
Remember, this
keyword of a method within an Object refers to the "owner" of the method that is the object itself. In the case of the above example,
it is the person object.
But, When we hold the reference of person.print
to another variable that is printRef
, it means that print
(refer to printThis function) is out of the person execution context. Now, the value of printRef()
will depend on where are we executing it.
If we execute it within the global context, the value will be the global window object (as demonstrated in the above example). It is also called implicit binding.
But, If we change the execution context explicitly then the value of this
will also change. The below example shows explicit
binding
function printThis(){ console.log(this); //window object } var person = { firstName: "John", lastName : "Doe", print : printThis, }; var newObj = { fname: "New John", lastName : "New Doe", } var printRef = person.print; printRef.call(newObj); //{fname: "New John", lastName: "New Doe"} OR var printRef = person.print.bind(newObj); printRef() //{fname: "New John", lastName: "New Doe"}
Now, let's assign printThis
method to the member of the Student constructor.
function printThis(){ console.log(this); //window object } function Student(){ this.name = "John"; this.print = printThis; }; var obj = new Student(); obj.print(); // {name: "John", print: Æ’}
In the above example, obj.print()
is nothing but the printThis()
function itself which is executing within the context of Student.
obj
is an object (instance) created from the Student constructor. If we invoke obj.print()
, it will print the instance of student
that is - Studnet object.
Within a constructor context, this
refers to the instance of that constructor.
function Student(){ this.name = "John"; this.print = function(){ console.log(this); } }; var obj = new Student(); obj.print(); // {name: "John", print: Æ’} obj instanceof Student; //true
We can use methods like- call()
, bind()
and apply()
to change the this
of any function.
These special methods execute the function in the provided object context.
var name = "name from window"; function Print(){ console.log(this.name); }; Print(); //name from window var obj = { name: "name from obj", } Print.call(obj);
call()
, bind()
and apply()
behaves differently than the new
Keyword. When we use new
keyword, it invoke the function as constructor and returns an object which contains whatever is
attached with this
within that function. If nothing is attached to this
keyword then it returns an empty object.
function Print(){ console.log(this.name); }; var obj = new Print(); console.log(obj) // {}
However, when we use call()
, bind()
and apply()
, it execute the function with new context instead
returing a object like new
keyword. call()
and apply()
execute the function immediately but, bind()
just bind the new context with the function and return the reference of that function which we can execute later.
A function's this
loses its context when executed within setTimeout
.
var name = "Global John"; var obj = { name: "John", print: function() { console.log(this.name); }, } obj.print(); //John setTimeout(obj.print, 2000); //Global John
As you can see, obj.print
is executing withing global context not the obj
context.
We can explicitly bind the "this" with the function'. In this example, it is obj
which we can bind with the function.
setTimeout(obj.print.bind(obj), 2000); //John
Let's see some more examples:-
var name = "Global John"; var obj = { name: "John", print: function() { setTimeout(() => { console.log(this.name); }, 2000); }, } obj.print();
Can you guess, what will be the output of the above code? Take some time and try to figure it out. Think in terms of the execution context.
output: John
Let's tweak the code. Let's use the arrow function within setTimeout.
var name = "Global John"; var obj = { name: "John", print: ()=> setTimeout(() => console.log(this.name), 2000), } obj.print(); //Global John
Just by changing the function to arrow function this
points to global context. This is because the arrow function does not have its
this
contest, instead it take it from from parent lexical scope.
I hope this article was helpful to you. Now you must be a little more confident than earlier.
0 Comments