One of the confusing topics in JavaScript is the 'this' keyword. A function's 'this' keyword behaves a little differently in JS compared to other languages. It also has some differences between strict mode and non-strict mode. Let's learn all about them in this article.
this
in JavaScript is a reserved keyword. In most cases, the value of this
is determined by how a function is called(runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called. The bind()
method can set the value of a function's this
regardless of how it's called, and arrow functions don't provide their own this
binding. Let's see how this
behaves in different contexts.
-
Global context In the global execution context (outside of any function),
this
refers to the global object whether instrict mode
or not. We can see this by simply typingthis
in the devtools of the browser.
this // Window {0: Window, window: Window, self: Window,...
We can also run console.log(this === window) // true
-
Function context Now, if we log
this
inside a function, we are going to get two different outputs based on if we are instrict mode
or not.
function myFunc() {
console.log(this);
}
myFunc(); // Window {0: Window, window: Window, self: Window,...,
So in a non-strict mode, we are getting the same global object in the case of browsers - it is window object like before. In JavaScript this
first looks for the value
in the function curly braces, when it does not find any value
there, then it goes outside of the function scope and looks for the value
which is in the global context of the global object. This behavior of this
could be a source of a bug. So, in order to solve the issue, we can use use strict
function myFunc() {
'use strict';
console.log(this);
}
myFunc(); // undefined
Let's get another example:
function someFunc() {
this.name = 'Rahim Shah';
}
someFunc();
window.name; // 'Rahim Shah'
As you can see from the above example this.name
attached the name
with the global object which is the window
object in the browser. In case of strict mode it will throw a TypeError: Cannot set properties of undefined
- As an object method When a function is called as a method of an object, it's
this
is set to the object the method is called on. In the following example, whencustomObj.message()
is invoked, inside the functionthis
is bound to thecustomObj
object.
const customObj = {
name: 'Rahim',
occupation: 'Developer',
message: function() {
console.log('Hey! my name is', this.name + ' and I am a ' + this.occupation);
}
}
customObj.message(); // 'Hey! my name is', Rahim and I am a Developer'
this
binding is only affected by the most immediate member reference. In the following example, let's call a function in a nested object.
const customObj = {
name: 'Rahim',
occupation: 'Developer',
nestedObj: {
name: 'Karim',
occupation: 'Engineer',
message: function() {console.log('Hi, my name is ' + this.name);}
}
}
If we call customObj.nestedObj.message();
we will get 'Hi, my name is karim'
back.
-
Class context The behavior of
this
in classes and functions is similar since classes are functions under the hood. Within a class constructor,this
is a regular object. All non-static methods within the class are added to the prototype ofthis
:
class Example {
constructor() {
const proto = Object.getPrototypeof(this);
console.log(Object.getOwnPropertyNames(proto));
}
first(){}
second(){}
static third(){}
}
new Example(); // ['constructor', 'first', 'second']
Note: Static methods are not properties of this. They are properties of the class itself.
- The
bind()
,call()
,apply()
method We can specifically bindthis
to an object with thecall()
, orapply()
method. For an example let's take our previous example of nested object.
const customObj = {
name: 'Rahim',
occupation: 'Developer',
nestedObj: {
name: 'Karim',
occupation: 'Engineer',
message: function() {console.log('Hi, my name is ' + this.name);}
}
}
If we run customObj.nestedObj.message()
we are going to get the name printed as 'karim' but what if we want the 'Rahim' name instead? We can use the call()
method to achieve the desired result.
customObj.nestedObj.message.call(customObj) // Hi, my name is Rahim
apply()
method will get the same result as above. Let's look at the bind()
method. Calling someFunc.bind(someObj)
creates a new function with the same body and scope as someFunc
, but where this
occurs in the original function, in the new function it is permanently bound to the first argument of bind
, regardless of how the function is being used.
function someFunc() {
return this.property;
}
const anotherObj = someFunc.bind({ property: 'some value'})
console.log(anotherObj()) // some value
-
Arrow functions In arrow functions,
this
will be set to the global object in the global code. In the following code,this
will return undefined:
const customObj = {
name: 'Rahim',
nestedObj = {
name: 'Karim',
msg: () => {console.log(this)}
}
}
If we runcustomObj.nestedObj.msg()
will return window
object in browsers.
Read about Closures in JavaScript.
Top comments (0)