Skip to content
Theory · Closures and this · lesson 6 of 11

this

Think about the word "I". When Ann says it, it means Ann; when Bob says it, it means Bob. The word itself does not remember who wrote it: its meaning is decided by whoever is speaking now.

The word this in a method works the same way. As you already know, a method called with a dot gets the object before the dot as this. But the same method stored in a constant loses its object:

JavaScript
"use strict";

const user = {
    name: "Ann",
    greet() {
        return `Hi, ${this.name}`;
    }
};

console.log(user.greet()); // Hi, Ann

const greet = user.greet;
console.log(greet()); // ✗
TEXT
TypeError: Cannot read properties of undefined (reading 'name')

This is the Node.js and Chrome text; Firefox and Safari word the message differently. The first call prints Hi, Ann, the second stops the program.

The call decides this

this is decided at the moment of the call, not where the function is written. It is a common interview question: "What is this equal to?" For a regular function the answer starts with "it depends on how it was called". Let's look at three calls.

A call with a dot

In the call user.greet() the object before the dot is user, so this is user. user is the one saying "I", and this.name reads its name.

A call without a dot

The constant greet holds the same function, but the call greet() has no dot, and so it has no object. What ends up in this depends on the mode:

  • in strict mode this is undefined, and reading undefined.name stops the program with a TypeError;
  • without "use strict", this gets the global object, a built-in object shared by the whole program.

In the second case there is no error, but the function still does not see the user's name.

A method as a callback

A method also loses its object when the method itself is passed as a callback. The call ["Bob"].forEach(user.greet) passes forEach only the function, and forEach calls it without a dot. It is like forwarding someone's message "I'll come" without a signature: you can no longer tell who "I" is.

The bind method

Every function has a bind method. The call user.greet.bind(user) does not run the function; it returns a new one whose this is always user, however it is called:

JavaScript
"use strict";

const user = {
    name: "Ann",
    greet() {
        return `Hi, ${this.name}`;
    }
};

const greet = user.greet.bind(user);
console.log(greet()); // Hi, Ann
console.log(["Bob", "Eve"].map(greet).join(" ")); // Hi, Ann Hi, Ann

Let's go step by step:

  1. user.greet.bind(user) returns a new function with user bound to it for good.
  2. greet() is called without a dot, yet prints Hi, Ann.
  3. map gets greet as a callback and calls it for each element without a dot. Each time this is user, so both results are Hi, Ann.

Arrow functions and this

An arrow function has no this of its own. It takes this from the code around it, the place where it is written. It has no "I" of its own: it speaks on behalf of the code it was written inside. That makes it a good callback inside a method:

JavaScript
"use strict";

const team = {
    name: "Red",
    members: ["Ann", "Bob"],
    labels() {
        return this.members.map((m) => `${m}-${this.name}`);
    }
};

console.log(team.labels().join(" ")); // Ann-Red Bob-Red

The arrow function is written inside the method labels, so its this is the this of the method, that is team. A regular function (m) { … } in this place would be called by map without a dot, and its this would be undefined.

Here the analogy with the word "I" stops working: a person cannot speak with someone else's "I", while an arrow function does nothing else.

Common mistake

A method in an object literal — the name for curly braces { … } with keys and values — is made an arrow function:

JavaScript
const box = {
    size: 3,
    getSize: () => this.size // ✗
};

console.log(box.getSize()); // undefined

There is no error, but the program prints undefined instead of 3. The arrow function takes this from the code around the literal, not from the object box. At the top level of a file in Node.js, this is an empty object, so this.size gives undefined, not an error. A call with a dot does not change that. If a method needs its own object, write it as a regular function, for example in the short form: getSize() { return this.size; }.

Key points

  • The call decides this: with a dot it is the object before the dot; without a dot, in strict mode, it is undefined.
  • A method stored in a variable or passed as a callback loses its object; bind returns a function with this bound for good.
  • An arrow function has no this of its own: it takes it from the code around it, so it suits a callback in a method but not a method itself.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way