Home/Blog/Web Development/Understanding “this” in JavaScript
Understanding “this” in JavaScript
Home/Blog/Web Development/Understanding “this” in JavaScript

Understanding “this” in JavaScript

11 min read
May 16, 2025
content
What is this in JavaScript?
Global context and this
Function context and this
Regular function context
Destructured function context
Constructor function context
Object literal method context
Class method context
The arrow function and this
Implicit, explicit, and default binding of this
Moving forward!

Key takeaways:

  • The keyword this in JavaScript refers to the execution context of a function, and its value depends on how the function is invoked rather than where it is defined.

  • Regular functions in the global scope use this to point to the global object, while in strict mode, this is undefined.

  • Constructor functions use this to refer to the newly created instance.

  • Object literal methods and class methods use this to refer to the object or class instance.

  • Arrow functions inherit this from their surrounding lexical context and do not create their own.

Have you ever written a JavaScript function, expected this to point to your object, and instead got undefined or the global object?

You’re not alone!

Understanding this in JavaScript can feel like debugging Schrödinger’s cat—it changes depending on how you view it.

Unlike languages like C++ or Java, where this typically refers to the current instance of a class or object in an object-oriented paradigm, JavaScript determines this dynamically based on the execution context. This shifting reference—whether in functions, methods, constructors, or arrow functions—can lead to unexpected behavior, making it crucial to understand how this works in different scenarios so you never have to guess again.

Note: JavaScript operates within two primary environments: Node.js and the browser. Throughout this blog, we’ll discuss JavaScript in general, explaining its behavior as it applies to both environments. We’ll make specific distinctions whenever its behavior varies based on the executing environment. Similarly, where applicable, we’ll differentiate between strict and non-strict modes to ensure a complete understanding of this.

If you’re interested in learning JavaScript in depth, you can explore a course or skill path that covers everything from the basics to advanced concepts. Educative’s comprehensive JavaScript skill path provides hands-on experience to help you master the language effectively.

Cover
Zero to Hero in JavaScript

JavaScript is a popular, in-demand, and widely used programming language today because of its simple syntax, modular nature, and ability to support all modern browsers. This path is perfect for you if you are new to programming. The path will teach you real-world problem-solving techniques and how to write step-by-step solutions in JavaScript. You will start by covering JavaScript's basic syntax and functionality to create basic programs. In the latter half, you will get a detailed overview of object-oriented programming to create scalable, modular, and cleaner code. Moreover, you will get hands-on experience practicing the implementations of commonly used data structures in JavaScript. Finally, you build a Tetris game step by step using modern JavaScript. By the end of this path, you will be able to write real-world programs in JavaScript and start your career as a JavaScript developer.

29hrs
Beginner
23 Challenges
33 Quizzes

What is this in JavaScript?#

The this keyword is a reference to the execution context of a function. Its value depends on how the function is called rather than where it is defined. This dynamic nature makes this both powerful and tricky.

Global context and this#

When JavaScript code executes at the root level (outside of any function or block) in a Node.js module, this typically refers to module.exports.

For example, if we execute console.log(this) at the root level of a Node.js module, we’ll see that this refers to module.exports. In a module, module.exports initially begin as an empty object. As we add variables or methods to it, it evolves from an empty state to containing values. To confirm that this indeed refers to module.exports, let’s append a function to it and then print both this and module.exports in the following code:

Node.js
console.log('Value of "this" at the start:', this);
console.log('Value of "module.exports" at the start:', module.exports);
// Adding a function to module.exports
module.exports.myFunction = function() {
console.log('Just a function!');
};
// Print both this and module.exports after adding a function
console.log('\nValue of "this" after adding a function:', this);
console.log('Value of "module.exports" after adding a function:', module.exports);

However, when JavaScript code executes at the global level (outside of any function or block) in a browser environment, this refers to the global window object.

Function context and this#

Five primary function contexts in JavaScript can affect the value of this.

Regular function context#

When a regular function is called in the global scope, this refers to the global object (window in browsers, global in Node.js).

Note: The global object depends on the JavaScript execution environment. In a web browser, it’s the window object, while in a Node.js environment, it’s the global object.

In the following code, we define a regular function named myFunction() and invoke it within the global scope. Execute the code to verify that this points to the global object. This behavior is expected because we’ve configured the following widget to run within the Node.js environment:

Node.js
//'use strict'
// Regular function context
function myFunction()
{
console.log('Value of "this" inside "myFunction":',this)
}
myFunction()

Note: The this keyword is undefined inside a standalone function if the JavaScript code runs in strict mode. To observe the behavior of this in strict mode, uncomment the 'use strict' in the code above at line 1 and run it.

Destructured function context#

When a method is extracted from an object using object destructuring and invoked directly, this inside the function usually refers to the global object. This happens because the extracted function loses its original context and is no longer associated with the object from which it was extracted. Consequently, if the method depends on this to access properties or methods of the original object, it can result in unexpected behavior or errors.

In the following code, we have a user object containing the name and email properties and a method called displayProfile() to log user details. Before proceeding, can you guess the code output without running it?

Node.js
// Destructured function context
const user = {
name: 'Alice',
email: 'alice@example.com',
displayProfile() {
console.log(`--> Name: ${this.name}, Email: ${this.email}`)
console.log('--> Value of "this" inside the "displayProfile" function: \n',this)
},
};
// Calling function on the user object
console.log('Calling "displayProfile" on the "user" object:')
user.displayProfile()
// Destructuring the displayProfile method
const { displayProfile } = user
// Calling the displayProfile method
console.log('\nCalling "displayProfile" after de-structuring:')
displayProfile()

Initially, we call the displayProfile() method directly on the user object, which correctly accesses its properties. You might have rightly guessed that after destructuring the displayProfile() method from the user object, calling the function results in this pointing to the global object. Because the global object does not possess the name and email properties, any references to them within the function return undefined.

Constructor function context#

When a function is used as a constructor (with the new keyword), this refers to the newly created instance of the object.

Node.js
// Constructor function context
function Product(price) {
this.price = price;
this.getInfo = function() {
console.log('--> Value of "this" inside the "getInfo" function: \n',this)
return this.price
};
}
const laptop = new Product(1200);
laptop.getInfo()

In the code above, we define a constructor function, Product, to create objects with a price property and a getInfo method to retrieve the price. When invoked with the new keyword, this inside the constructor refers to the newly created instance of the object. Therefore, when getInfo is called on the laptop object, this points to the laptop object itself, allowing access to its price property.

Object literal method context#

When a method is defined within an object literal, this refers to the object itself, allowing access to other properties and methods of the same object using this.

Node.js
//Object literal method context
const recipe = {
title: 'Chocolate Cake',
displayTitle() {
console.log(`--> Recipe: ${this.title}`);
console.log('--> Value of "this" inside the "displayTitle" function: \n',this)
},
};
recipe.displayTitle();

In the code above, we define an object literal named recipe with a title property and a displayTitle() method to log the recipe title. When displayTitle() is invoked on the recipe object, this inside the method refers to the recipe object itself. Therefore, this.title accesses the title property of the recipe object, allowing the method to display the recipe title correctly.

Class method context#

When a function is called as a method of a class object, this refers to the class instance that owns the method.

Node.js
// Class method context
class BankAccount {
constructor(owner, balance) {
this.owner = owner
this.balance = balance
console.log('--> Value of "this" inside the "constructor": \n',this)
}
deposit(amount) {
this.balance += amount;
console.log(`Deposit of $${amount} successful. New balance: $${this.balance}`)
console.log('--> Value of "this" inside the "deposit" function: \n',this)
}
}
const myAccount = new BankAccount('John Doe', 1000)
myAccount.deposit(500)

The above code defines a BankAccount class with a constructor to initialize the owner and balance properties. When an instance of BankAccount is created using the new keyword, this inside the constructor refers to the newly created instance. Similarly, the deposit() method of the class operates on the instance’s properties, and this within the method points to the instance itself. Therefore, calling deposit() on myAccount correctly updates the balance property of the instance.

The following diagram provides a summary of the various function contexts:

Summary of function contexts
Summary of function contexts

The arrow function and this#

In JavaScript, arrow functions work differently with the this keyword than regular functions. An arrow function doesn’t make its own this. Instead, it uses the this from where it is already written in its surroundings. This makes arrow functions practical in scenarios where keeping track of this is important, such as handling events or using callbacks. When an arrow function is passed as a callback, the this value is preserved and remains the same throughout the callback function’s execution. This preservation of the this value holds true even if the callback is executed later or triggered by a future event.

For example, consider the following code, where we simulate a user login. The User object’s login method uses an arrow function as a callback within the setTimeout function. Despite the delay, this value is valid and refers to the User object, ensuring the isLoggedIn property is updated correctly.

Node.js
const User = {
name: 'John',
isLoggedIn: false,
login() {
// Set isLoggedIn to true after a 2-second delay
setTimeout(() => {
this.isLoggedIn = true;
console.log(`${this.name} has logged in successfully!`);
}, 2000);
}
};
User.login();

What if a regular function is used within setTimeout instead of an arrow function? We’ve replicated the same behavior in the following code. Can you predict its output without executing it?

Node.js
const User = {
name: 'John',
isLoggedIn: false,
login() {
// Set isLoggedIn to true after a 2-second delay
setTimeout(function() {
this.isLoggedIn = true;
console.log(`${this.name} has logged in successfully!`);
console.log('\n--> Value of "this" inside the "callback" function: \n',this)
}, 2000);
}
};
User.login();

If a regular function is used within setTimeout instead of an arrow function, this points to the Timeout object rather than the User object. This happens because regular functions create their own this context, which is determined by how the function is called. When setTimeout calls the callback function, it does so in the context of the Timeout object. This also means that the callback is executed outside the scope of the User object. Therefore, within the setTimeout callback function, this refers to the Timeout object, not the User object. Consequently, attempting to update the isLoggedIn property fails, leading to unexpected behavior.

Difference between the arrow and regular function callbacks
Difference between the arrow and regular function callbacks


The following table summarizes the behavior of the this keyword in different function contexts we’ve explored so far:

Context

Behavior

Global Context

The this keyword refers to module.exports (Node.js) or global window (browser) object.

Function Context

Regular function: The this keyword refers to the global (Node.js) or window (browser) object.

Destructured function: The global keyword (Node.js) or window (browser) object.

Constructor function: The this keyword refers to a newly created instance of the object.

Object literal method: The this keyword refers to the object itself.

Class method: The this keyword refers to the class instance that owns the method.

Arrow Function

The this keyword retains the value from the lexical context where it’s defined.

Implicit, explicit, and default binding of this#

Implicit binding automatically assigns this inside a function to the object preceding the dot during the function call. For example, when invoking a function using dot notation, like object.method(), this refers to object.

Explicit binding involves manually defining this within a function using methods like call(), apply(), or bind(). These methods allow precise control over this, irrespective of how the function is called. This intentional step is helpful when handling changing function environments or when we want to use the same function with different objects.

Explicit binding methods
Explicit binding methods

To understand explicit binding methods better, let’s explore how bind(), call(), and apply() can be used to precisely control this inside functions.

  • bind(): This generates a fresh function, where this is explicitly defined by passing an object as an argument. When this newly created function is called, this is bound to the provided object.
    For example, in the following code snippet, the function calculateTotal() calculates the total price of items in a shopping cart. Note that calculateTotal() is a standalone function. If called, the context of this inside calculateTotal() would typically refer to the global object, leading to potential errors or unexpected behavior.
    To address this concern, the bind() method is utilized. The bind() method is used to create two new functions, calculateTotalForCart1, and calculateTotalForCart2, by generating fresh instances of the original calculateTotal() function. These new functions explicitly define this by passing an object as an argument, ensuring that when invoked, they maintain a context bound to cart1 and cart2, respectively.

Node.js
function calculateTotal(currencySymbol) {
let total = 0;
this.items.forEach(item => {
total += item.price;
});
console.log(`Total: ${currencySymbol}${total}`);
}
const cart1 = {
items: [
{ name: 'Shirt', price: 20 },
{ name: 'Jeans', price: 30 },
{ name: 'Shoes', price: 50 }
]
};
const cart2 = {
items: [
{ name: 'Book', price: 15 },
{ name: 'Pen', price: 5 },
{ name: 'Notebook', price: 10 }
]
};
// Using explicit binding with the bind() method to create new functions bound to shopping carts
const calculateTotalForCart1 = calculateTotal.bind(cart1, '$');
const calculateTotalForCart2 = calculateTotal.bind(cart2, '€');
// Using the newly bound functions to calculate total for different shopping carts
calculateTotalForCart1(); // Total: $100
calculateTotalForCart2(); // Total: €30
  • call(): This immediately calls the method, and this is bound to the object passed as an argument. It’s useful when we want to invoke a function with a specific this context without creating a new function.
    In the following code, the call() method is used to explicitly specify the context (this value) when invoking the sendEmail() function for user1 and user2, ensuring emails are sent immediately to the correct recipients.

Node.js
function sendEmail(message, priority) {
console.log(`Sending email to ${this.email} with message: ${message} and priority: ${priority}`);
}
const user1 = {
email: 'user1@example.com',
name: 'Alice'
};
const user2 = {
email: 'user2@example.com',
name: 'Bob'
};
const message = 'Hello, this is a reminder email.';
const priority = 'high';
// Using explicit binding with the call() method to send emails to different users
sendEmail.call(user1, message, priority);
sendEmail.call(user2, message, priority);
  • apply(): This is similar to call() because it immediately calls the method, and this is bound to the object passed as an argument. The main difference between call() and apply() lies in how arguments are passed to the invoked function. With call(), arguments are passed individually and separated by commas, whereas with apply(), arguments are passed as an array.
    In the following code, sendEmail.call() directly invokes sendEmail for user1, with message and priority passed as arguments. Conversely, sendEmail.apply() achieves the same result but accepts the arguments within the array [message, priority].

Node.js
function sendEmail(message, priority) {
console.log(`Sending email to ${this.email} with message: ${message} and priority: ${priority}`);
}
const user1 = {
email: 'user1@example.com',
name: 'Alice'
};
const user2 = {
email: 'user2@example.com',
name: 'Bob'
};
const message = 'Hello, this is a reminder email.';
const priority = 'high';
// Using explicit binding with the call() method to send emails to different users
sendEmail.call(user1, message, priority);
sendEmail.call(user2, message, priority);
// Using explicit binding with the apply() method to send emails to different users
sendEmail.apply(user1, [message, priority]);
sendEmail.apply(user2, [message, priority]);

Default binding sets the this keyword to the global object when a function is called on its own without any specific context. This happens in the global scope when a function is invoked directly without using dot notation or explicit binding methods like call(), apply(), or bind().

In the following example, when we first invoke announce() without a specific context, this is set to the global object by default. So, when it tries to find this.department, it can’t, and it prints “Attention, undefined department!”. We use call(department) to fix this in the second announce() call. It binds the department object to this to find the department property.

Node.js
//'use strict'
function announce() {
console.log(`Attention, ${this.department} department!`);
}
const department = {
department: 'Marketing',
announce: announce
};
announce(); // 'this' inside announce is by default attached to the 'global' object
announce.call(department) // 'this' inside announce is bound to the 'department' object

Note: Uncomment 'use strict' at line 1 in the provided code to observe that accessing this.department will result in a runtime exception. In JavaScript’s strict mode, this defaults to undefined in the global function context.

The following table summarizes the behavior of the this keyword in different binding contexts, aiding you in referencing and applying this more effectively:

Context

Behavior

Implicit Binding

The this keyword inside a function is automatically assigned to the object before the dot during the function call.

Explicit Binding

Methods like call(), apply(), and bind() are employed to manually designate this within a function.

Default Binding

When a function is invoked independently, this defaults to the global (Node.js) or window (browser) object.

We hope this exploration has helped you understand the often confusing concept of using this in various execution contexts and platforms within JavaScript. Our practical code examples were designed to offer you hands-on explanations of these concepts.

Moving forward!#

We encourage you to continue your learning journey and deepen your understanding of JavaScript by exploring our extensive catalog of courses and learning paths on Educative. Our platform offers comprehensive resources tailored to support learners at every stage of their JavaScript proficiency. You can explore how our practical content can help you unlock your full potential as a JavaScript developer.

Some of the latest courses available on our platform include:

Frequently Asked Questions

What does the ${} syntax mean in JavaScript?

The ${} syntax is used in JavaScript with template literals to perform string interpolation. It lets you embed expressions, variables, or function calls directly into a string by enclosing them within ${}. Template literals are enclosed in backticks (`), making the syntax more readable and versatile than traditional string concatenation.

Example:

const name = "John";
console.log(`Hello, ${name}!`); // Output: Hello, John!

What does the this keyword do?

The this keyword in JavaScript represents the execution context of a function or an object. Its value changes based on where and how it is used:

  • Inside a method, this refers to the object that owns the method.
  • In a regular function (non-strict mode), this refers to the global object (e.g., window in browsers).
  • In a regular function (strict mode), this is undefined.
  • In an arrow function, this is inherited from the surrounding lexical scope.

Why is the ${} syntax used in JavaScript template literals?

The ${} symbol is used in template literals to simplify embedding dynamic content into strings. It avoids the clunky syntax of concatenating strings with the + operator, making the code cleaner and easier to read.

Example of concatenation vs. template literals:

const age = 25;
	
// Using concatenation
console.log("I am " + age + " years old."); // Output: I am 25 years old.
	
// Using template literals
console.log(`I am ${age} years old.`); // Output: I am 25 years old.

Written By:
Ishrat Fatima

Free Resources