this Keyword in JavaScript

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-strictmode: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
Strictmode:"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
undefinedbut as I had already told you that if the value ofthisisundefinedit will be forced to becomeglobal objectso that’s way when we simply callwhatWillBeThis()in strict mode it logsundefinedand in non-strict mode it logsglobal object. This process where the value ofthisis 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: undefinedNon-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,
thisis determined at the time of function execution, depending on who calls the function.In arrow functions,
thisis 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
objobject had called theregularfunction so thethisrefer to thisobjobject inregularfunction.But you might be confuse why the
thisinsidearrowfunction is global object (windowin browser and{}in nodejs), the value ofthisinside arrow function should be the reference toobjobject like it was in the regular function.Yes, you are right in some sense but as I told you
arrowfunction take(or inherit)thisfrom there surrounding scope. So, when we had defined thearrowfunction, the value ofthisin it’s surrounding scope refers to theglobal objectso thearrowfunction 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
thiscontext so inlogNamefunction we havesetTimeoutand in it we pass regular functioninsideSetTimeoutas a callback so it creates it’s ownthiswhich iswindow objectin browser for same reason (context being undefined) andTimeoutobject in nodejs as nodejs had different implementation ofsetTimeout.But for arrow function they take
thisfrom there scope so when we callobj.logNameArrowfunction, thethisinsidelogNameArrowrefer toobjso the callback function insidesetTimeoutis anarrowfunction which take thisobjobject as it’sthiscontext because this is the value ofthisin thearrowfunction 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
sayNamenormal function takes this fromperson1as thisperson1object calls him.The
sayNameArrowarrow function takesthisfrom its surrounding scope and inside constructor function, thethisrefers to theperson1object soarrowfunction takeperson1as it’sthisvalue.
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
thiskeywordMDN
strictmode



