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),
thisrefers to the global object whether instrict modeor not. We can see this by simply typingthisin 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
thisinside a function, we are going to get two different outputs based on if we are instrict modeor 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
thisis set to the object the method is called on. In the following example, whencustomObj.message()is invoked, inside the functionthisis bound to thecustomObjobject.
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
thisin classes and functions is similar since classes are functions under the hood. Within a class constructor,thisis 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 bindthisto 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,
thiswill be set to the global object in the global code. In the following code,thiswill 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)