Understanding the this Keyword in JavaScript
Introduction
The this keyword is one of the most confusing concepts in JavaScript for beginners. It appears in almost every JavaScript program, but its meaning changes depending on where and how it's used. Understanding this is crucial because it affects how your code behaves, especially when working with objects and methods. In this blog, we'll demystify the this keyword by exploring what it represents, how it changes based on context, and how to use it effectively in your code.
1. What Does this Represent?
The this keyword in JavaScript represents the object that is executing the current function. Think of this as a way for a function to know who called it.
Simple Analogy:
Imagine you're a teacher and you ask a student "What's your name?" The student who hears the question answers with their own name. In this case, "you" (the question) is like this - it refers to whoever is being addressed at that moment.
In JavaScript, this refers to the object that is currently calling or executing the function.
A Basic Example:
const person = {
name: "Isha",
greet: function() {
console.log("Hello, I am " + this.name);
}
};
person.greet(); // Output: Hello, I am Isha
Here, this refers to the person object because person is calling the greet function. The greet function doesn't inherently know its own name, but this tells it "you are being called by the person object."
Key Concept:
this is determined by how a function is called, not by where the function is defined.
const person1 = {
name: "Raj",
introduce: function() {
return "I am " + this.name;
}
};
const person2 = {
name: "Priya"
};
// Same function, different callers
console.log(person1.introduce()); // "I am Raj"
// Now assign the function to person2
person2.introduce = person1.introduce;
console.log(person2.introduce()); // "I am Priya"
The same function behaves differently depending on who calls it. That's the power of this.
2. this in the Global Context
When this is used outside of any object or function, it refers to the global object.
In Browsers:
The global object is called window.
console.log(this); // window object
var globalVar = "I am global";
console.log(this.globalVar); // "I am global"
console.log(window.globalVar); // "I am global"
When you declare a variable with var at the top level (not inside a function or object), it becomes a property of the global object.
In Node.js:
The global object is called global.
console.log(this); // global object
var globalVar = "I am global";
console.log(this.globalVar); // "I am global"
console.log(global.globalVar); // "I am global"
A Function in Global Context:
function displayThis() {
console.log(this);
}
displayThis(); // window (in browser) or global (in Node.js)
When a function is called without an object before it, this refers to the global object.
Important Note:
If you use const or let instead of var, the variable is not added to the global object:
let globalLet = "With let";
var globalVar = "With var";
console.log(this.globalLet); // undefined
console.log(this.globalVar); // "With var"
This is one reason why modern JavaScript prefers let and const over var.
3. this Inside Objects
When a function is called as a method of an object, this refers to that object.
Basic Object Method:
const car = {
brand: "Toyota",
model: "Fortuner",
displayInfo: function() {
console.log(this.brand + " " + this.model);
}
};
car.displayInfo(); // Output: Toyota Fortuner
Here, this refers to the car object because car.displayInfo() is calling the function.
Accessing Multiple Properties:
const student = {
name: "Arjun",
age: 20,
city: "Bangalore",
introduce: function() {
console.log("My name is " + this.name);
console.log("I am " + this.age + " years old");
console.log("I live in " + this.city);
}
};
student.introduce();
// Output:
// My name is Arjun
// I am 20 years old
// I live in Bangalore
Modifying Object Properties:
const bank = {
balance: 5000,
deposit: function(amount) {
this.balance = this.balance + amount;
console.log("New balance: Rs." + this.balance);
},
withdraw: function(amount) {
this.balance = this.balance - amount;
console.log("New balance: Rs." + this.balance);
}
};
bank.deposit(2000); // New balance: Rs.7000
bank.withdraw(1500); // New balance: Rs.5500
Notice how this.balance refers to the balance property of the bank object. Without this, the function wouldn't know which object's balance to update.
Nested Objects:
const company = {
name: "Tech Solutions",
department: {
name: "Engineering",
getInfo: function() {
console.log("Department: " + this.name); // Refers to department object
}
}
};
company.department.getInfo(); // Output: Department: Engineering
Important: this refers to the immediate parent object (the one directly calling the method), not the outer object.
4. this Inside Functions
Functions can be called in different ways, and the value of this depends on how they're called.
Function Called Without an Object:
function sayMyName() {
console.log("My name is: " + this.name);
}
var name = "Global Name";
sayMyName(); // Output: My name is: Global Name
When a function is called without an object, this refers to the global object (window in browsers, global in Node.js).
Function Called with an Object:
const person = {
name: "Deepak",
greet: sayMyName
};
function sayMyName() {
console.log("My name is: " + this.name);
}
person.greet(); // Output: My name is: Deepak
Now this refers to the person object because person.greet() called the function.
The Problem: Losing Context
This is where things get tricky. When you store a function in a variable, it can lose its context:
const phone = {
brand: "Samsung",
getBrand: function() {
return this.brand;
}
};
console.log(phone.getBrand()); // "Samsung"
// Store the function in a new variable
const myFunction = phone.getBrand;
console.log(myFunction()); // undefined or "Global Brand" (if exists)
Why? Because myFunction() is called without an object, so this is the global object, not the phone object.
Passing Functions as Arguments:
const restaurant = {
name: "Spice House",
greetCustomer: function() {
console.log("Welcome to " + this.name);
}
};
// This works
restaurant.greetCustomer(); // Welcome to Spice House
// This doesn't work
setTimeout(restaurant.greetCustomer, 1000);
// Output: Welcome to undefined
// Because setTimeout calls the function, not the restaurant object
The Solution: Arrow Functions
Arrow functions have special behavior with this. They don't have their own this. Instead, they inherit this from the surrounding code:
const restaurant = {
name: "Spice House",
greetCustomer: function() {
// Regular function
console.log("Welcome to " + this.name);
},
greetWithArrow: () => {
// Arrow function - inherits this from outer scope
console.log("Welcome to " + this.name);
}
};
restaurant.greetCustomer(); // Welcome to Spice House
restaurant.greetWithArrow(); // Welcome to undefined
Arrow functions are useful in callbacks where you want to preserve the this value from the outer function.
5. How Calling Context Changes this
The most important rule: this is determined by how the function is called, not where it's defined.
Rule 1: Method Call (Object Calling the Function)
const user = {
username: "vikram_007",
login: function() {
console.log(this.username + " logged in");
}
};
user.login(); // this = user
// Output: vikram_007 logged in
When you use object.method(), this is the object.
Rule 2: Function Call (No Object)
function login() {
console.log(this.username + " logged in");
}
login(); // this = global object
// Output: undefined logged in
When you call a function directly, this is the global object.
Rule 3: Using the call() Method
The call() method lets you explicitly specify what this should be:
function introduce() {
console.log("Hello, I am " + this.name);
}
const person1 = { name: "Neha" };
const person2 = { name: "Arjun" };
introduce.call(person1); // this = person1, Output: Hello, I am Neha
introduce.call(person2); // this = person2, Output: Hello, I am Arjun
Rule 4: Using the apply() Method
apply() is similar to call(), but you pass arguments as an array:
function introduce(greeting, hobby) {
console.log(greeting + ", I am " + this.name + " and I like " + hobby);
}
const person = { name: "Priya" };
introduce.apply(person, ["Hello", "coding"]);
// Output: Hello, I am Priya and I like coding
Rule 5: Using the bind() Method
bind() creates a new function with this permanently set:
function greet() {
console.log("Hi, I am " + this.name);
}
const person = { name: "Rohan" };
const boundGreet = greet.bind(person);
boundGreet(); // Output: Hi, I am Rohan
// Even if you call it without an object, this still works
const anotherRef = boundGreet;
anotherRef(); // Output: Hi, I am Rohan
bind() is very useful when passing functions as callbacks, because it locks in the this value.
Practical Example: Event Handlers
const button = {
label: "Click Me",
handleClick: function() {
console.log(this.label + " was clicked");
}
};
// This won't work - this will be the button element, not our object
// document.getElementById("myBtn").addEventListener("click", button.handleClick);
// Solution 1: Use bind()
document.getElementById("myBtn").addEventListener("click", button.handleClick.bind(button));
// Solution 2: Use an arrow function (which preserves this)
document.getElementById("myBtn").addEventListener("click", () => {
button.handleClick();
});
6. Common this Mistakes and How to Avoid Them
Mistake 1: Losing Context When Storing a Method
const game = {
score: 0,
increaseScore: function() {
this.score++;
console.log("Score: " + this.score);
}
};
game.increaseScore(); // Works: Score: 1
const fn = game.increaseScore;
fn(); // Broken: this is undefined or global object
Solution: Use bind()
const fn = game.increaseScore.bind(game);
fn(); // Works: Score: 2
Mistake 2: this in Nested Functions
const user = {
name: "Maya",
init: function() {
console.log(this.name); // "Maya" - correct
function innerFunction() {
console.log(this.name); // undefined - wrong!
}
innerFunction();
}
};
user.init();
Solution: Use an arrow function or save this
const user = {
name: "Maya",
init: function() {
console.log(this.name); // "Maya"
// Solution 1: Arrow function
const inner1 = () => {
console.log(this.name); // "Maya" - correct
};
inner1();
// Solution 2: Save this
const self = this;
function inner2() {
console.log(self.name); // "Maya" - correct
}
inner2();
}
};
user.init();
Mistake 3: Arrow Functions in Object Methods
const car = {
brand: "BMW",
// Wrong: Arrow function doesn't get this from the object
displayBrand: () => {
console.log(this.brand); // undefined
},
// Correct: Regular function gets this from the object
displayBrandCorrect: function() {
console.log(this.brand); // "BMW"
}
};
car.displayBrand(); // undefined
car.displayBrandCorrect(); // "BMW"
Rule: Use arrow functions for callbacks, regular functions for object methods.
7. this in Different Scenarios
In Constructor Functions:
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
console.log("Hi, I am " + this.name);
};
}
const p1 = new Person("Arjun", 25);
const p2 = new Person("Priya", 23);
p1.greet(); // Hi, I am Arjun
p2.greet(); // Hi, I am Priya
When using new, this refers to the newly created object.
In Classes:
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
getSalaryInfo() {
return this.name + " earns Rs." + this.salary;
}
}
const emp = new Employee("Vikram", 50000);
console.log(emp.getSalaryInfo()); // Vikram earns Rs.50000
In classes, this works similarly to constructor functions.
In Array Methods with Callbacks:
const numbers = [1, 2, 3, 4, 5];
// Using regular function
numbers.forEach(function(num) {
console.log(this); // global object (or window)
});
// Using arrow function
const obj = {
multiplier: 2,
multiplyNumbers: function() {
numbers.forEach((num) => {
console.log(this.multiplier); // Refers to obj (correct)
});
}
};
obj.multiplyNumbers();
8. Visual Guide: How this Changes
Here's a quick reference for determining this:
METHOD CALLED AS: VALUE OF this:
===============================================
object.method() the object
function() global object
obj1.obj2.method() obj2 (immediate parent)
method.call(obj, ...) obj (explicitly set)
method.apply(obj, [...]) obj (explicitly set)
method.bind(obj) obj (locked in)
new Constructor() the new object
arrow => {} inherited from outer scope
Examples:
const config = {
debug: true,
log: function() {
console.log(this.debug); // true
}
};
// Method call
config.log(); // this = config
// Function call
const fn = config.log;
fn(); // this = global object
// Using call
fn.call(config); // this = config
// Using bind
const boundFn = fn.bind(config);
boundFn(); // this = config
9. Practical Real-World Example
Let's build a practical example that combines all these concepts:
const account = {
accountNumber: "1234567890",
balance: 10000,
owner: "Rajesh Kumar",
// Method to display account info
getInfo: function() {
console.log("Account: " + this.accountNumber);
console.log("Owner: " + this.owner);
console.log("Balance: Rs." + this.balance);
},
// Method to deposit money
deposit: function(amount) {
this.balance += amount;
console.log("Deposited Rs." + amount);
console.log("New balance: Rs." + this.balance);
},
// Method to withdraw money
withdraw: function(amount) {
if (amount <= this.balance) {
this.balance -= amount;
console.log("Withdrawn Rs." + amount);
console.log("New balance: Rs." + this.balance);
} else {
console.log("Insufficient balance");
}
},
// Method to set up automatic transactions
setupAutoTransaction: function() {
// Using arrow function to preserve this
const auto = () => {
console.log("Auto transaction for " + this.owner);
this.deposit(1000);
};
// Simulate auto transaction after 2 seconds
setTimeout(auto, 2000);
}
};
// Using the account
account.getInfo();
// Output:
// Account: 1234567890
// Owner: Rajesh Kumar
// Balance: Rs.10000
account.deposit(5000);
// Output:
// Deposited Rs.5000
// New balance: Rs.15000
account.withdraw(3000);
// Output:
// Withdrawn Rs.3000
// New balance: Rs.12000
account.setupAutoTransaction();
// Output (after 2 seconds):
// Auto transaction for Rajesh Kumar
// Deposited Rs.1000
// New balance: Rs.13000
10. Debugging this
If you're confused about what this is in your code, here's how to debug it:
function myFunction() {
console.log("this is:", this);
console.log("this.name is:", this.name);
}
const obj = { name: "TestObject" };
myFunction(); // Log this to see what it is
obj.myFunction = myFunction;
obj.myFunction(); // Log this again
Pro Tip: Use console.log(this) or add debugger statements to see exactly what this refers to in any situation.
Conclusion
The this keyword is one of the most important concepts in JavaScript, but it's not magic. Just remember these key points:
thisrefers to the object that is calling the functionIn global context,
thisis the global object (window or global)Inside object methods,
thisis the objectthisis determined by how the function is called, not where it's definedUse
call(),apply(), orbind()to explicitly setthisArrow functions don't have their own
this, they inherit it from the surrounding scope
Understanding this will make you a better JavaScript developer. It's used everywhere in real-world code, so investing time to understand it now will pay off tremendously in the future. Start practicing with simple examples, and gradually build up to more complex scenarios.




