Understanding this in JavaScript
JavaScript’s `this` keyword often confuses developers because its value changes depending on how and where a function is called. Let’s break down its behavior, rules, and best practices to avoid common pitfalls.
Join the 2.000+ members who have already signed up.
What is `this`?
`this` refers to the execution context of a function. Its value isn’t fixed – it’s determined when the function is invoked. Sounds complicated? No worries it isn’t, it’s based on these simple rules.
Rule 1: Global Context
Outside any function, `this` refers to the global object (`window` in browsers, `global` in Node.js).
console.log(this); // In a browser: Window {...}
⚠️ ATTENTION: In strict mode (’use strict’;), global`this` is `undefined`
‘use strict’;
console.log(this); // undefined (in global scope)
Rule 2: Function Context
In a standalone function, `this` depends on how the function is called:
function sayHello() {
console.log(this); /* Window (or global object) */
}
sayHello(); // Called in global scope
Using strict mode:
'use strict';
function sayHello() {
console.log(this); // undefined
}
sayHello();
Rule 3: Object Context
When a function is a method of an object, `this` refers to the object itself:
const user = {
name: "Alice",
greet() {
console.log(`Hello, ${this.name}!`);
}
};
user.greet(); // "Hello, Alice!"
Pitfall: Losing Context ⚠️
If you extract the method, `this` becomes
disconnected:
const greet = user.greet;
greet(); // "Hello, undefined!" (this refers to global/undefined)
FIX: Use `bind` to lock the context:
const boundGreet = user.greet.bind(user);
boundGreet(); // "Hello, Alice!"
Rule 4: Arrow Functions
Arrow functions do not have their own `this`. They inherit `this` from the surrounding lexical scope:
const user = {
name: "Bob",
greet: () => {
console.log(this.name); // Inherits global/window `this`
}
};
user.greet(); // undefined (if strict mode) or ""
Better for Callbacks:
const button = document.querySelector(‘button’);
button.addEventListener(‘click’, function() {
console.log(this); // Refers to the button element
});
// Arrow function would inherit `this` from outer scope (e.g., window):
button.addEventListener('click', () => {
console.log(this); // Not the button!
});
Rule 5: Constructor Functions (Classes)
When using `new`, `this` refers to the newly created instance:
function Person(name) {
this.name = name;
}
const alice = new Person('Alice');
console.log(alice.name); // "Alice"
In Classes:
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hi, ${this.name}!`);
}
}
const bob = new User('Bob');
bob.greet(); // "Hi, Bob!"
Rule 6: Explicit Binding
Force `this` to a specific object using `call`, `apply`, or `bind`:
function describe(lang) {
console.log(`${this.name} codes in ${lang}`);
}
const dev = { name: "Charlie" };
describe.call(dev, ‘JavaScript’); // "Charlie codes in JavaScript"
describe.apply(dev, [‘Python’]); // "Charlie codes in Python"
const boundDescribe = describe.bind(dev);
boundDescribe('Ruby'); // "Charlie codes in Ruby"
Common Mistakes & Fixes.
1. Nested Functions loosing `this`
const timer = {
seconds: 10,
start() {
setInterval(function() {
console.log(this.seconds--); // `this` is global here and don’t points to
// the timer object anymore
}, 1000);
}
};
timer.start(); // NaN (this.seconds is undefined)
Fix: Use an arrow function or `bind`:
// Arrow function (inherits `this` from `start`):
setInterval(() => {
console.log(this.seconds--);
}, 1000);
// Or bind:
setInterval(function() {
console.log(this.seconds--);
}.bind(this), 1000);
// binds the timer object context to the function
2. Event Handlers
In DOM event handlers, `this`
refers to the element triggering the event:
const timer = {
seconds: 10,
start() {
setInterval(function() {
console.log(this.seconds--);
// `this` is global here and don’t points to
// the timer object anymore
}, 1000);
}
};
timer.start(); // NaN (this.seconds is undefined)
Key Takeaways & Conclusion
So what’s the most important lesson of all this?
- `this` is determined by how a function is called, not where it’s defined.
- Use arrow functions to preserve lexical `this` (e.g., in callbacks).
- Explicitly set `this` with `bind`, `call`, or `apply` when needed.
- Avoid using `this` in standalone functions – it’s often a source of bugs.
Conclusion
How to use the this object can be tricky due to its dependencies within its context, but the best way to improve your understanding of the `this` keyword is to play around with it. Therefore use the code snippets to play around and see it in action. – Cheers