Methods are functions stored as object properties. When you call a method, JavaScript sets the this keyword to the object the method was called on.
Understanding this is one of the most confusing parts of JavaScript. It becomes simple once you learn the rules.
this in methods
When a function is called as a method, this refers to the object before the dot:
const counter = {
count: 0,
increment() {
this.count++;
return this.count;
},
};
counter.increment(); // 1
counter.increment(); // 2
Inside increment, this refers to counter because the call was counter.increment(). The object before the dot becomes this.
this depends on how a function is called
The same function can have different this values depending on how it is invoked:
function showThis() {
console.log(this);
}
const obj = { showThis };
showThis(); // global object (or undefined in strict mode)
obj.showThis(); // obj
The function is the same. What changes is the call site. this is determined at call time, not at definition time.
Losing this in callbacks
The most common this bug happens when you pass a method as a callback:
const counter = {
count: 0,
increment() {
this.count++;
},
};
setTimeout(counter.increment, 100);
// TypeError: Cannot read properties of undefined (reading 'count')
When counter.increment is passed to setTimeout, it is called as a plain function, not as a method. There is no object before the dot, so this is undefined (in strict mode) or the global object.
Fix 1: Use an arrow function wrapper
setTimeout(() => counter.increment(), 100);
// works — increment is called as counter.increment()
Fix 2: Use bind
bind creates a new function with this permanently set:
setTimeout(counter.increment.bind(counter), 100);
// works — this is bound to counter
Fix 3: Use arrow function methods
Arrow functions do not have their own this — they inherit it from the surrounding scope:
const counter = {
count: 0,
increment: function() {
this.count++;
},
};
This does not change anything because increment is a regular function. But when you use arrow functions in callbacks inside methods, this is preserved:
const counter = {
count: 0,
start() {
setInterval(() => {
this.count++; // arrow inherits `this` from start(), where this = counter
}, 1000);
},
};
this in the global context
In the global context (code not inside a function), this refers to the global object:
console.log(this); // window in browsers, global in Node.js
In strict mode (which modules use by default), this is undefined in the global context:
"use strict";
console.log(this); // undefined
this in event handlers
In DOM event handlers, this refers to the element that the listener is attached to:
button.addEventListener("click", function() {
console.log(this); // the button element
});
If you use an arrow function for the event handler, this is inherited from the surrounding scope instead:
button.addEventListener("click", () => {
console.log(this); // whatever `this` was in the outer scope
});
Use regular functions when you need this to be the element. Use arrow functions when you need this to be the component or object the handler belongs to.
Rules for determining this
- Method call (
obj.method()) —thisis the object before the dot - Plain function call (
func()) —thisisundefined(strict mode) or the global object - Arrow function —
thisis inherited from the enclosing scope bind—thisis whatever you passed tobindcall/apply—thisis the first argument passed to the method- Event handler (regular function) —
thisis the element the listener is on - Event handler (arrow function) —
thisis inherited from the outer scope
const counter = {
count: 0,
increment: () => {
this.count++; // this is NOT counter — it is undefined or global
},
};
Use regular function syntax for object methods. Use arrow functions for callbacks inside those methods.
What to carry forward
thisrefers to the object the method was called on — the object before the dotthisis determined at call time, not definition time- passing a method as a callback loses the
thisbinding - fix lost
thiswith arrow function wrappers,bind, or arrow function callbacks - arrow functions do not have their own
this— they inherit from the enclosing scope - in event handlers,
thisis the element for regular functions, inherited for arrow functions - use regular functions for object methods; use arrow functions for callbacks
Understanding this is essential for working with objects, classes, and DOM event handlers. The next lesson covers the prototype chain in more depth.
Quick Check
One answerWhat mainly determines the value of this for a regular JavaScript function?
Choose the best answer and use it to track your progress through the lesson.
Why that answer is correct
For regular functions, `this` is decided by the call site. That is why passing a method as a plain callback often loses the original object binding.