this Keyword in Javascript
9/13/2025
Demystifying the this Keyword in JavaScript
Welcome! This guide is designed to give you a rock-solid understanding of one of JavaScript's most powerful, yet often misunderstood, concepts: the this keyword.
We’ll explore the rules, exceptions, and interview-style puzzles with examples.
📖 What is this?
thisis a special keyword in JavaScript that refers to an object.- The value of
thisis dynamic: it depends not on where the function is defined, but on how it’s called.
👉 Think of this like the pronoun he/she/they: its meaning changes depending on context.
🔑 The Four Rules of this Binding
We’ll use the following vivek object throughout:
const vivek = {
name: 'Vivek',
role: 'Software Engineer',
languages: ['JavaScript', 'Python', 'Java'],
introduce: function() {
console.log(`Hi, I'm ${this.name}, and I'm a ${this.role}.`);
}
};
1. Implicit Binding (Dot Rule)
When a function is called as a method (via dot), this is the object to the left of the dot.
vivek.introduce();
// Output: Hi, I'm Vivek, and I'm a Software Engineer.
2. Explicit Binding (call, apply, bind)
You can force a function’s this.
function describeLanguages() {
console.log(`${this.name} codes in: ${this.languages.join(', ')}.`);
}
describeLanguages.call(vivek);
// Vivek codes in: JavaScript, Python, Java.
const boundFn = describeLanguages.bind(vivek);
boundFn();
// Vivek codes in: JavaScript, Python, Java.
3. new Binding (Constructor Functions)
When called with new, a function creates an object, and this refers to it.
function SoftwareEngineer(name, company) {
this.name = name;
this.company = company;
}
const virat = new SoftwareEngineer('Virat', 'Google');
console.log(virat.name); // Virat
4. Default Binding (Fallback)
If none of the other rules apply:
- Non-strict → global object (
windowin browsers). - Strict →
undefined.
function showMeThis() {
console.log(this);
}
showMeThis();
// window (browser) or global (Node)
'use strict';
function strictFn() {
console.log(this);
}
strictFn();
// undefined
⚡ The Big Exception: Arrow Functions
- Arrow functions do not bind their own
this. - Instead, they inherit
thisfrom the enclosing scope.
const project = {
name: 'Project Javasctipt',
team: ['Vivek', 'Virat'],
showTeam: function() {
this.team.forEach(member => {
console.log(`${member} is on ${this.name}`);
});
}
};
project.showTeam();
// Vivek is on Project Javasctipt
// Virat is on Project Javasctipt
If we had used a regular function inside forEach, this would not refer to project.
🎯 Binding Precedence
If multiple rules apply, precedence is:
newbinding →thisis the new object.- Explicit binding →
.call,.apply,.bind. - Implicit binding → object before dot.
- Default binding → global or undefined.
👉 Arrow functions are special—they don’t follow these rules.
🧠 Tricky Interview Questions & Output Puzzles
Q1. Losing context
const vivek = {
name: 'Vivek',
greet: function() {
console.log(`Hello, ${this.name}!`);
}
};
const sayHello = vivek.greet;
sayHello();
Answer: Hello, undefined! (strict mode) or Hello, ! (non-strict global).
Context is lost because sayHello is a plain function call → default binding.
Q2. Callback Conundrum
const vivek = {
name: 'Vivek',
tasks: ['Code', 'Debug', 'Deploy'],
printTasks: function() {
this.tasks.forEach(function(task) {
console.log(`${this.name} needs to ${task}`);
});
}
};
vivek.printTasks();
Answer:
needs to Code
needs to Debug
needs to Deploy
Because the callback function falls back to default binding. Fix: use arrow functions.
Q3. Arrow function as method
const vivek = {
name: 'Vivek',
role: 'Software Engineer',
getDetails: () => {
console.log(`Name: ${this.name}, Role: ${this.role}`);
}
};
vivek.getDetails();
Answer: Name: undefined, Role: undefined
Arrow functions don’t have their own this → this comes from the global scope.
Q4. Explicitly binding arrow functions
const vivek = { name: 'Vivek' };
const sayName = () => console.log(this.name);
sayName.call(vivek);
Answer: undefined
Arrow functions ignore .call/.apply/.bind.
Q5. Precedence puzzle
'use strict';
function Person(name) {
this.name = name;
this.speak = function() {
console.log(`I am ${this.name}`);
}
}
const vivek = new Person('Vivek');
const virat = { name: 'Virat' };
vivek.speak.call(virat);
Answer: I am Virat
Explicit binding (.call) overrides implicit binding.
Q6. Constructor returning an object
function Person(name) {
this.name = name;
return { name: 'Overridden' };
}
const vivek = new Person('Vivek');
console.log(vivek.name);
Answer: Overridden
Returning an object explicitly replaces the constructed this.
Q7. setTimeout gotcha
const vivek = {
name: "Vivek",
greet: function () {
setTimeout(function () {
console.log("Hi " + this.name);
}, 0);
}
};
vivek.greet();
Answer: Hi undefined
Because this inside the callback defaults to global.
Fix with an arrow function.
✅ Key Takeaways
thisis not lexical (except with arrow functions).- Context matters: how you call determines
this. - Binding precedence:
new> explicit > implicit > default. - Arrow functions "capture"
thisfrom their enclosing scope. - Common pitfalls: callbacks, event handlers, assigning methods to variables.