this is a special keyword whose value depends on how a function is called, not where it is written. That is why it confuses everybody at first. Start with the common cases.
Inside an object method
When you call a function as a method (object.method()), this is the object before the dot.
const user = {
name: "Maya",
greet() {
return "Hi, I am " + this.name;
}
};
console.log(user.greet()); // → Hi, I am Maya
The problem: losing this
If you take the method out of the object, the connection is gone.
const user = {
userName: "Maya",
greet() {
return "Hi, I am " + this.userName;
}
};
const detached = user.greet;
console.log(detached()); // → Hi, I am undefined
Called by itself, this is no longer user. (In strict mode it is undefined and the line throws an error instead.) This happens all the time when you pass a method as a callback.
Fixing it
1. bind() creates a new function with this fixed.
const user = {
name: "Maya",
greet() { return "Hi, I am " + this.name; }
};
const bound = user.greet.bind(user);
console.log(bound()); // → Hi, I am Maya
2. An arrow function around the call.
const user = {
name: "Maya",
greet() { return "Hi, I am " + this.name; }
};
const run = () => user.greet();
console.log(run()); // → Hi, I am Maya
Arrow functions do not have their own this
They use the this from the surrounding code. That makes them ideal inside methods:
const list = {
items: ["a", "b"],
prefix: "item:",
show() {
this.items.forEach(item => console.log(this.prefix, item));
}
};
list.show();
But it also means an arrow function is a poor choice as an object method that needs this:
const broken = {
name: "Maya",
greet: () => "Hi " + this.name // `this` is NOT the object
};
this in event listeners
In a normal function used as an event listener, this is the element that received the event.
button.addEventListener("click", function () {
console.log(this === button); // true
});
Inside an arrow function it is not. Many developers use event.currentTarget instead, which works in both. See The Event Object.
Quick rules
| How the function is called | this is |
|---|---|
obj.method() | obj |
method() on its own | undefined (strict mode) or the global object |
new Fn() | the new object |
| Arrow function | this of the surrounding code |
fn.call(x), fn.bind(x) | x |
Do not fear it
this ever gives you undefined, ask: “how was this function called?” The answer is nearly always a lost method.