this Keyword in JavaScript

Table of contents

The this
keyword refers to the context where a piece of code is running.
OR
this
keyword batata hai ki kaha pe (context) code run kar raha hai.
The value of this
in JavaScript depends on where the function is invoked or called, not where it is defined. For example:
When a regular function is invoked as a method of object
(obj.method()
), this points to that object
.
const obj = {
name: "John",
age: 30,
method() {
console.log(this); // {name: 'John', age: 30, method: ƒ} (refering to object)
return `Name is ${this.name} and age is ${age}`
}
}
console.log(obj.method()). // Name is John and age is 30
When invoked as a standalone function (not attached to any object: obj.functionName()
), this
typically refers to the global object (in non-strict mode) or undefined
(in strict mode).
In
non-strict
mode:function tellMeWhatIsThis() { console.log(this) } tellMeWhatIsThis() // Global Object in case of Browser which is window // Window {window: Window, self: Window, document: document, name: '', location: Location, …} // In case of Node js // Node js Global Object // To see Node js global object you can do "console.log(globalThis)"
In
Strict
mode:"use strict" function tellMeWhatIsThisInStrictMode() { console.log(this) } tellMeWhatIsThisInStrictMode() // undefined (both browser and nodejs)
When we simply logs this
in the global scope it refers to global
object in browser, and empty parenthesis {}
in the node js environment.
console.log(this)
// Global Object in case of Browser which is window
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// Nodejs
// {}
this
keyword in Strict v/s Non-Strict Mode
this
keyword behave differently in strict and non-strict mode.
In Non-Strict Mode
The value of this
in non-strict mode is forced to be an object. If the value of this
is already an object
then this object becomes the value of this
. If the value of this
is null
or undefined
then the new value of this
becomes global object
and if the value of this
is any primitive value, then this primitive value is wrapped (or boxed) to there corresponding wrapper object.
NOTE
In JavaScript, "boxing" refers to the process where a primitive value (like a number, string, or boolean) is wrapped inside an there wrapper object.
function whatWillBeThis() {
console.log(this)
}
whatWillBeThis() // Global Object (window in browser)
whatWillBeThis.call(null) // Global Object (window in browser)
whatWillBeThis.call(undefined) // Global Object (window in browser)
whatWillBeThis.call(42) // Number {42}
whatWillBeThis.call("String") // String {'String'}
whatWillBeThis.call(true) // Boolean {true}
whatWillBeThis.call(3n) // BigInt {3n}
whatWillBeThis.call(Symbol("symbol")) // Symbol {Symbol(symbol), description: 'symbol'}
In Strict Mode
In strict mode, the value of this
is not forced to be an object. If the value of this
is undefined
then it will be undefined
, if it is null
then it will be null
and if it is any primitive value then these primitive values will also be not boxed into there wrapper object and the value of this
will simply be that primitive value.
"use strict"
function whatWillBeThis() {
console.log(this)
}
whatWillBeThis() // undefined
whatWillBeThis.call(null) // null
whatWillBeThis.call(undefined) // undefined
whatWillBeThis.call(42) // 42
whatWillBeThis.call("String") // "String"
whatWillBeThis.call(true) // true
whatWillBeThis.call(3n) // 3n
whatWillBeThis.call(Symbol("symbol")) // Symbol(symbol)
IMPORTANT POINT
In JavaScript when you simply call the function the value of this inside it is
undefined
but as I had already told you that if the value ofthis
isundefined
it will be forced to becomeglobal object
so that’s way when we simply callwhatWillBeThis()
in strict mode it logsundefined
and in non-strict mode it logsglobal object
. This process where the value ofthis
is getting replaced by objects in non-strict mode is also referred to as this substitution.
So, now if I tell you the difference between strict and non-strict mode in JavaScript, it simply is in non-strict mode this substitution
takes place and in strict mode no this substitution
takes place.
this
keyword in Node v/s Browser
this
keyword also behave different in Node js and in Browser. In Node js all modules (or script files) are executed in their own module scope which is an empty object {}
while browsers execute all script files directly within the global scope so this
is window
. Read more about it here:
console.log(this)
// Browser
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// Nodejs
// {}
The below picture shows the value of this
in browser and in nodejs:
Strict Mode
"use strict" console.log("this outside function: ", this) function tellMeValueOfThis() { console.log("this inside function: ", this) } tellMeValueOfThis() // Browser // this outside function: Window {window: Window, self: Window, document: document, name: '', location: Location, …} // this inside function: undefined // Node js // this outside function: {} // this inside function: undefined
Non-Strict Mode
console.log("this outside function: ", this) function tellMeValueOfThis() { console.log("this inside function: ", this) } tellMeValueOfThis() // Browser // this outside function: Window {window: Window, self: Window, document: document, name: '', location: Location, …} // this inside function: Window {window: Window, self: Window, document: document, name: '', location: Location, …} // Node js // this outside function: {} // this inside function: Node js Global Object
this
keyword in context of Normal Function
Inside the function, the value of this
depends on how the function is called.
For a regular function, the value of this
is the object that had called the function. For example if there is an object that had a method defined in it, then the value of this
inside that method will be the object that had called
the function. For example:
If function call is in the form of obj.f()
, then this
inside f
function refers to obj
.
Consider this code:
let obj = {
name: "Aditya",
age: 44,
getDetails() {
console.log("The value of this: ", this) // The value of this: {name: 'Aditya', age: 44, getDetails: ƒ}
return `My name is ${this.name} and age is ${this.age}`
}
}
console.log(obj.getDetails()) // My name is Aditya and age is 44
The value of this
will not be the object that had defined the function as his own property but the object that had call the function. In other words, if obj
had defined function name getThis
and we create a another object objTwo
and sets it prototype to obj
and then call the function getThis
then the value of this would the object that had call the function.
Consider this code:
// Defined a obj with function as it's own property
const obj = {
name: "obj",
getThis() {
return this
}
}
// Defined another object and set it's prototype to "obj"
const objTwo = {
name: "objTwo",
age: 33
}
// set objTwo parent (or prototype) to obj
Object.setPrototypeOf(objTwo, obj)
// The "getThis" method is defined in "obj" but the "objTwo" object had called it
// so the value of "this" is "objTwo" object.
console.log(objTwo.getThis()) // {name: 'objTwo', age: 33}
The value of this
always changes based on how a function is called, even when the function was defined in another object at creation:
const obj4 = {
name: "obj4",
getThis() {
return this;
},
};
const obj5 = { name: "obj5" };
obj5.getThis = obj4.getThis;
console.log(obj5.getThis()); // { name: 'obj5', getThis: [Function: getThis] }
this
keyword in context of Callbacks
When a function is passed as a callback, the value of this
depends on how the callback is called. Callbacks are typically called with a this
value of undefined
as they are called directly without attaching any object, which means if the function is non–strict, the value of this
is the global object (globalThis
). This is the case for iterative array methods, the Promise()
constructor, etc.
In non-strict
mode, when we pass callback
function, the value of this
is undefined
in most cases and because of logic I had explained above the value of this
become Global Object
.
// NON-STRICT MODE
const arr = [1, 2, 3, 4, 5]
function getThis() {
console.log(this)
}
// "getThis" function is passed as a callback to forEach array method
arr.forEach(getThis)
// It will run 5 fives and each time will log the value of this
// Iteration 1: Window {window: Window, self: Window, document: document, name: '', …} or Global object in nodejs
// Iteration 2: Window {window: Window, self: Window, document: document, name: '', …} or Global object in nodejs
// Iteration 3: Window {window: Window, self: Window, document: document, name: '', …} or Global object in nodejs
// Iteration 4: Window {window: Window, self: Window, document: document, name: '', …} or Global object in nodejs
// Iteration 5: Window {window: Window, self: Window, document: document, name: '', …} or Global object in nodejs
// "logThis" function is passed as a callback to "Promise" constructor
const promise = new Promise(function logThis(resolve, reject) {
console.log("this in promise: ", this);
resolve("Successful");
})
// this in promise: Window {window: Window, self: Window, document: document, name: '', …} or Global object in nodejs
In strict
mode, when we pass callback
function, the value of this
is undefined
in most cases and because of logic I had explained above the value of this
does not change.
// STRICT MODE
"use strict"
const arr = [1, 2, 3, 4, 5]
function getThis() {
console.log(this)
}
// "getThis" function is passed as a callback to forEach array method
arr.forEach(getThis)
// It will run 5 fives and each time will log the value of this
// Same for both NodeJs and browser
// Iteration 1: undefined
// Iteration 2: undefined
// Iteration 3: undefined
// Iteration 4: undefined
// Iteration 5: undefined
// "logThis" function is passed as a callback to "Promise" constructor
const promise = new Promise(function logThis(resolve, reject) {
console.log("this in promise: ", this);
resolve("Successful");
})
// this in promise: undefined
this
keyword in context of Arrow function
The arrow
function does not have there own this
binding, they take the value of this
from there surrounding scope (or surrounding lexical scope). Now, the word surrounding scope
is the most important to keep in mind as it will help you to know what will be the value of this
inside the arrow function.
Arrow functions create closure of the surrounding scope.
Key Differences from Regular Functions:
In regular functions,
this
is determined at the time of function execution, depending on who calls the function.In arrow functions,
this
is determined at the time of function definition, based on where the function is written or defined in the code.
For example consider this code:
// In NON-STRICT MODE
// Regular function
function normal() {
return this
}
// Arrow function
const arrow = () => {
return this
}
console.log("The value of this in regular function: ", normal())
// The value of this in regular function: (same for Nodejs also)
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
console.log("The value of this in arrow function: ", arrow())
// The value of this in arrow function:
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// {} (output empty parenthesis for node js as in it module scope is there)
By seeing this example you might think they both are giving the same value of this
. Yes, they are giving the same value but there is different reason for why they both are giving same value of this
.
For regular function, as I had told you that when you simply call them they does not have any context so the value of this
inside them is undefined
but as we are in non-strict
mode it get replaced by global object
due to this substitution.
For arrow function, as they do not have there own this
so they take this from there surrounding scope (or surrounding lexical scope). Now, in above example the function arrow
was defined in global scope in browser and module scope in node js and in browser this
in global scope refer to window object
and in node js this
in module scope refer to {}
empty parenthesis so the function arrow
logs window object
in browser and {}
empty parenthesis in nodejs.
Now, again take this example
// In STRICT MODE
"use strict"
// Regular function
function normal() {
return this
}
// Arrow function
const arrow = () => {
return this
}
console.log("The value of this in regular function: ", normal())
// The value of this in regular function: (same for Nodejs also)
// undefined
console.log("The value of this in arrow function: ", arrow())
// The value of this in arrow function:
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// {} (output empty parenthesis for node js as in it module scope is there)
As now, you can see in strict
mode when no this substitution take place the normal function logs undefined
but for arrow function as it does not have it’s own this
binding so it again take this
from it’s scope which is global scope and that’s why it again logs the window object
in browser and {}
empty parenthesis in nodejs.
this
in Regular function v/s Arrow function
This section explains how the regular and arrow function behave differently.
Inside an Object Method
const obj = { name: "Aditya", age: 60, regular() { return this; }, arrow: () => { return this } } console.log("this in regular fn: ", obj.regular()) // this in regular fn: // Browser: {name: 'Aditya', age: 60, tellThisTruthInsideObject: Window Object, regular: ƒ, arrow: ƒ} // NodeJS: {name: 'Aditya', age: 60, tellThisTruthInsideObject: {}, regular: ƒ, arrow: ƒ} console.log("this in arrow fn: ", obj.arrow()) // this in arrow fn: // Browser: Window {window: Window, self: Window, document: document, name: '', location: Location, …} // NodeJS: {}
I think you know the reason for the results that regular function shows. As the
obj
object had called theregular
function so thethis
refer to thisobj
object inregular
function.But you might be confuse why the
this
insidearrow
function is global object (window
in browser and{}
in nodejs), the value ofthis
inside arrow function should be the reference toobj
object like it was in the regular function.Yes, you are right in some sense but as I told you
arrow
function take(or inherit)this
from there surrounding scope. So, when we had defined thearrow
function, the value ofthis
in it’s surrounding scope refers to theglobal object
so thearrow
function inherits this value. For example
In this code, I have defined an obj
object inside a function and we will try to set different value of this
inside in function to show that arrow
function defined inside the obj
object take the value of this
from it’s scope. Read about call
here.
function SetThisContext() {
console.log("this in outer scope: ", this);
const obj = {
arrow: () => {
return this
}
}
console.log("this in arrow fuction: ", obj.arrow())
}
// Both "this in outer scope" and "this in arrow fuction" refers to same value.
SetThisContext() // Global Object
SetThisContext.call("String") // String {'String'}
SetThisContext.call(33) // Number {33}
SetThisContext.call(true) // Boolean {true}
Inside a callback function
const obj = { name: "Emma", logName: function() { setTimeout(function insideSetTimeout() { console.log("this in regular fn: ", this) }, 1000) }, logNameArrow: function() { console.log("logNameArrow this: ", this); // logNameArrow this: {name: 'Emma', logName: ƒ, logNameArrow: ƒ} setTimeout(() => { console.log("this in arrow fn: ", this) }, 1000) } } obj.logName() // this in regular fn: // Browser: Window {window: Window, self: Window, document: document, name: '', location: Location, …} // NodeJS: SetTimeout Timeout {} object obj.logNameArrow() // this in arrow fn: // Browser: {name: 'Emma', logName: ƒ, logNameArrow: ƒ} // NodeJS: {name: 'Emma', logName: ƒ, logNameArrow: ƒ}
A regular function always creates it’s own
this
context so inlogName
function we havesetTimeout
and in it we pass regular functioninsideSetTimeout
as a callback so it creates it’s ownthis
which iswindow object
in browser for same reason (context being undefined) andTimeout
object in nodejs as nodejs had different implementation ofsetTimeout
.But for arrow function they take
this
from there scope so when we callobj.logNameArrow
function, thethis
insidelogNameArrow
refer toobj
so the callback function insidesetTimeout
is anarrow
function which take thisobj
object as it’sthis
context because this is the value ofthis
in thearrow
function surrounding scope.
Inside a constructor function
function Person(name) { this.name = name; console.log("this inside Person: ", this); // Person {name: 'David', sayName: ƒ, sayNameArrow: ƒ} this.sayName = function () { console.log(this); }; this.sayNameArrow = () => { console.log(this); }; } const person1 = new Person("David"); person1.sayName(); // Person {name: 'David', sayName: ƒ, sayNameArrow: ƒ} person1.sayNameArrow(); // Person {name: 'David', sayName: ƒ, sayNameArrow: ƒ}
The
sayName
normal function takes this fromperson1
as thisperson1
object calls him.The
sayNameArrow
arrow function takesthis
from its surrounding scope and inside constructor function, thethis
refers to theperson1
object soarrow
function takeperson1
as it’sthis
value.
Inside a class
class Person { constructor(name) { this.name = name; console.log("this: ", this); // this: {name: 'Bob', arrowMethod: ƒ} } regularMethod() { console.log(this.name); // Works } arrowMethod = () => { console.log(this.name); // Works because `this` is inherited }; } const person = new Person("Bob"); person.regularMethod(); // {name: 'Bob', arrowMethod: ƒ} person.arrowMethod(); // {name: 'Bob', arrowMethod: ƒ}
Same reason as the constructor
Conclusion
The this
keyword in JavaScript is dynamic and depends on how a function is called. In regular functions, it is determined by the caller, in arrow function it is determined where the arrow function is defined while in strict mode, it can be undefined
instead of the global object.
Reference
MDN
this
keywordMDN
strict
mode
Subscribe to my newsletter
Read articles from Ridam Singhal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
