Introduction
When I started my journey as a JavaScript developer, one of the most confusing concepts I struggled with was the use of the ‘this’ keyword. It came across to change its behavior depending on where and how it was used, sometimes pointing to an object, to undefined, and other times to the window object. I kept getting errors and unexpected results. At one point, I considered avoiding it altogether.
Understanding ‘this’ is an important concept in JavaScript and is foundational for mastering the language.
But as I dove deeper into frameworks like React, I realized I could not escape ‘this.’ I had to learn it, and once I did, it became one of the most powerful tools in my developer’s toolbox. So, whether you are just starting or brushing up, let me walk you through everything I have learned about ‘this’ in a way I wish someone had explained to me before.
What is ‘this’ in JavaScript
In simple terms, ‘this’ is a reference to an object that is available in the block or lexical scope of a function. The value of ‘this’ is determined by the function context and the way the function is invoked.
Think of this as a context pointer; it points to who is calling the function. Its value depends on how a function is called, not where it is written. Understanding the function definition and the current execution context is key to predicting what ‘this’ will refer to.
Why is ‘this’ Important
Knowing how ‘this’ works allows you to:
- Access object properties inside methods.
- Write more reusable and maintainable code.
- Understand and use classes, event handlers, and framework-specific code (like React, Vue).
- Avoid common bugs and improve debugging.
Use Cases of ‘this’ in JavaScript
1. Global Scope
console.log(this) // In browser: Window, In Node: {}
Global scope of ‘this’ refers to the global window object that consists of browser window properties and functions.
2. In a Regular Function
console.log(this);
}show();
When you call show()directly (not as a method of an object), the value of ‘this’ depends on whether you are in strict or non-strict mode.
In non-strict mode, ‘this’ refers to a global object (window object for browsers).
In strict mode, ‘this’ is undefined, because the strict mode prevents ‘this’ from defaulting to the global object in standalone function calls.
‘use strict’;function show() {
console.log(this); // undefined
}show();
3. In Event Listeners
console.log(this); // Button element
});
In the above illustration, we are adding event listener on a button with id = myBtn. When an event triggers, the callback function is called. In this situation, ‘this’ refers to the element that receives the event, and the button element is returned.
Important difference with arrow functions
If you use an arrow function rather:
console.log(this); // window object
});
Arrow functions do not have their own ‘this’. They take ‘this’ from the outer or lexical scope where arrow functions are defined. So, here, ‘this’ would generally be the window object (or whatever the lexical scope’s ‘this’ is).
4. Inside an Object Method
name: ‘Rishi’,
greet() {
console.log(`Hi, I’m ${this.name}`);
}
};user.greet();
In this illustration, we have an object user with a property name and method greet. When you call user.greet(), JavaScript looks at how the function is called. Since you are calling it through the object (user.greet()), the keyword ‘this’ inside that function points to the object user.
The output is: Hi, I’m Rishi
If we take the function reference and call it separately
name: ‘Rishi’,
greet() {
console.log(`Hi, I’m ${this.name}`);
}
};const greetFunc = user.greet;
greetFunc(); // Hi, I’m undefined, this refers to window object
Now ‘this’ does not point to the user anymore, so this.name becomes undefined because points to the window object.
5. Inside an Arrow Function
name: ‘Rishi’,
greet: () => {
console.log(`Hi, I’m ${this.name}`); // undefined
}
};user.greet();
In this illustration, method greet is defined using the arrow function. As we know, the arrow function does not have its own ‘this,’ so ‘this’ refers to its lexical scope. In our case, the arrow function’s lexical scope is object literal. But object literal does not create its own ‘this’ binding. Hence, ‘this’ inside greet comes from the object’s lexical scope where the object is defined. In our case ‘this’ is the window object that does not have the name property.
The output is: Hi, I’m undefined
6. With Call, Apply, and Bind
console.log(`Hello, ${this.name}`);
}const person = { name: “Rishi” };
greet.call(person); // Hello Rishi
greet.apply(person); // Hello Rishiconst greetRef = greet.bind(person);
greetRef(); // Hello Rishi
In this illustration, we are controlling ‘this’ explicitly using .call(), .apply(), and .bind() methods.
.call(thisArg, …args) calls the function immediately with the ‘this’ value you provide. In our example, ‘this’ is a person.
.apply(thisArg, [argsArray]) is nearly the same as .call(). The only difference is that .call() takes arguments as comma separated, whereas .apply() takes arguments as an array.
.bind(thisArg, …args) does not call the function immediately. Instead, it creates a new function where ‘this’ is permanently set to the value you give (person).
Use Cases of ‘this’ in JavaScript
React class components rely heavily on ‘this.’
❌ Problem Example
constructor(props) {
super(props);
this.state = { count: 0 };
}increment() {
this.setState({ count: this.state.count + 1 });
}render() {
return ;
}
}
Without binding, this.increment loses the context of the class, leading to a runtime error.
✅ Bind increment function with class ‘this’ instance:
constructor(props) {
super(props);
this.state = { count: 0 };
this.increment = this.increment.bind(this);
}increment() {
this.setState({ count: this.state.count + 1 });
}render() {
return ;
}
}
Class methods do not bind ‘this’ by default. When you pass a method like increment as callback or event listener, the context of ‘this’ is not preserved, unless you explicitly bind it.
✅ Fix Using Arrow Function
constructor(props) {
super(props);
this.state = { count: 0 };
}increment = () => {
this.setState({ count: this.state.count + 1 });
};render() {
return ;
}
}
As we know, arrow functions do not have their own ‘this,’ It refers ‘this’ to its lexical scope. In our case, arrow function’s lexical scope is MyComponent class.
Best Practices for Using ‘this’
Mastering the ‘this’ keyword in JavaScript is all about using it intentionally and consistently. Here are some best practices to help you avoid common pitfalls and write robust, efficient code:
- Use this to access the properties and methods of the current object, especially within object methods and class instances.
- When you need to explicitly set the value of this, use the bind() method to create a bound function with a specific context.
- Leverage arrow functions to inherit this from the surrounding scope, which is especially useful in callbacks and nested functions.
- Avoid relying on this in the global scope, as its value can be confusing and may lead to unexpected results, especially in strict mode.
- Use console.log(this) to inspect the current value of this during development and debugging.
- Enable strict mode in your code to prevent accidental binding of this to the global object and to catch errors early.
- Use the new keyword to create new objects and ensure that this refers to the newly created instance.
- Access the global object in a cross-platform way using globalThis, which works in both browsers and Node.js.
- Maintain a consistent coding style and use tools like linters to catch mistakes in your use of this.
- When defining functions, be clear about whether you want this to refer to the global object, a specific object, or to be inherited from the enclosing context.
- Remember that using call(), apply(), or bind() allows you to control the context in which a function is executed.
- Always be aware of the execution context and how it affects the value of this, especially when passing functions as callbacks or event handlers.
By following these best practices, you’ll be able to harness the full power of the ‘this’ keyword in JavaScript, avoid common errors, and write code that is both efficient and easy to understand.
❌ Cons:
- You may introduce subtle bugs.
- Event handlers in React may break.
- Misuse can lead to memory leaks.
You will struggle with OOP (Object-Oriented Programming) and class inheritance.
✅ Pros:
- Write cleaner, context-aware code.
- Debug errors faster.
- Use frameworks and advanced patterns confidently.
Conclusion
If you truly want to become a professional JavaScript developer, understanding ‘this’ is non-negotiable. It might feel frustrating at first (trust me, I have been there), but once it clicks, it unlocks a whole new level of clarity in writing and understanding code.
So do not ignore ‘this’ — embrace it, experiment with it, and it will make you a better JavaScript and React developer.
Know More: Embedded Software Development Services






