Bitsy Explains
Home/JavaScript, Explained Like You're Five/Lesson 16

The this Keyword in JavaScript

Inside a regular function, this means the object before the dot when you call it. Learn how this gets lost, and how bind and arrow functions help.

Lesson 16 of 203 min readVideo
Video thumbnail: The this Keyword Watch the 90-second video
Explain like I'm five

When Bitsy says "me", it means Bitsy. When Bob says "me", it means Bob. Same word, different person. The this keyword works the same way, so one function can be shared by many objects and still know which one is using it.

this is the object before the dot

A method is a function that lives inside an object. Inside a method, this is the object before the dot when you call it.

const robot = {
  name: "Bitsy",
  greet() {
    return this.name;
  },
};
console.log(robot.greet()); // prints: Bitsy

You called robot.greet(). The object before the dot is robot, so this is robot, and this.name is "Bitsy".

One function, many objects

This is the reason this changes. You can write a function once and share it between objects. Each time it runs, this points at whichever object called it.

function greet() {
  return "Hi, I'm " + this.name;
}
const bitsy = { name: "Bitsy", greet };
const bob = { name: "Bob", greet };
console.log(bitsy.greet()); // prints: Hi, I'm Bitsy
console.log(bob.greet()); // prints: Hi, I'm Bob

Same function, same word, different object. So this depends on how you call the function, not on where you wrote it.

The trap: losing this

Take the function out of the object and call it on its own. Now there is nothing before the dot, so this is lost.

const robot = {
  name: "Bitsy",
  greet() {
    "use strict";
    return this.name;
  },
};
const greet = robot.greet;
greet();

The "use strict" line turns on strict mode, the safer setting most modern code uses. Code inside classes and JavaScript modules is always strict. In strict mode, this is undefined here, so this.name throws TypeError: Cannot read properties of undefined (reading 'name'). Without strict mode, this falls back to the global object, and you quietly get the wrong name, usually undefined or an empty string.

This happens more often than you'd think. Passing a method somewhere else, like setTimeout(robot.greet, 1000), hands over the bare function, and the dot is gone by the time it gets called.

The twist: bind and arrow functions

You can glue this in place with bind. It gives you a new function where this is always the object you chose.

const robot = {
  name: "Bitsy",
  greet() {
    return this.name;
  },
};
const greet = robot.greet.bind(robot);
console.log(greet()); // prints: Bitsy

Now greet always knows it belongs to robot, however you call it.

Arrow functions are different. They don't have their own this at all. They use the this of the code around them. That makes them a good fit for callbacks inside a method.

const robot = {
  name: "Bitsy",
  friends: ["Bob", "Mia"],
  greetAll() {
    return this.friends.map(f => this.name + " waves at " + f);
  },
};
console.log(robot.greetAll()); // prints: [ 'Bitsy waves at Bob', 'Bitsy waves at Mia' ]

The arrow function borrows this from greetAll, which was called as robot.greetAll(), so this is robot.

A quick checklist

When you're not sure what this is, ask how the function was called.

  • Called with a dot, like robot.greet(): this is the object before the dot.
  • Made with bind: this is the object you passed to bind, every time.
  • An arrow function: this is whatever it is in the code around the arrow.
  • Called on its own, like greet(): this is undefined in strict mode, or the global object otherwise.

Most bugs with this come from the last case, a method that lost its dot along the way.

Rule of thumb

For regular functions, look at what is before the dot when you call it, and that is this.

Common mistake

Writing a method as an arrow function, like greet: () => this.name. The arrow has no this of its own, so it does not point at the object. Use the method shorthand greet() { ... } for methods.

Check yourself

With const robot = { name: "Bitsy", greet() { return this.name; } }, what is this when you call robot.greet()?