Wrong References to `this`

Valerie M.

The Problem

The this keyword is used in JavaScript to refer to an object. The object it refers to depends on how this is being invoked. The following table shows the different global and function contexts that this can be used:

Where this is calledWhat it refers to
Object methodThe object
Used aloneThe global object
In a functionThe global object
In a function (strict)undefined
In an eventThe element receiving event

In light of the above uses of this, there are bound to be problems where the this keyword ends up referring to the wrong object. We’re going to explore how these incorrect references come about and how to fix them.

The Solution

To understand how wrong references to this can occur, let’s look at the following code example where this is used when working with functions:

function myFunction() { return this; } // returns "[object Window]"

In the above example, this refers to the global object, which is an open browser window.

In strict mode, as shown below, this becomes undefined because default binding is not allowed. In this case, this should be used in objects you created.

'use strict'; function myFunction() { return this; } // returns "undefined"

The use of this is further explained below in the case of using it inside an object method.

const person = { firstName: 'John', lastName: 'Doe', id: 1, fullName() { return `${this.firstName} ${this.lastName}`; }, }; // Outputs "John Doe" console.log(person.fullName());

If you want to output a person’s full name, this is used and will refer to the person object.

However, things can become confusing when you want to use nested functions inside an object:

const person = { firstName: 'John', lastName: 'Doe', id: 1, fullName() { function name() { this.firstName = 'Jane'; return this; } const p = name(); return `${this.firstName} ${p.firstName}`; }, }; // Outputs "John Jane" console.log(person.fullName());

The above code outputs the result as expected because of object method binding, where each reference to this is bound to the firstName of the calling object where:

  • this.firstName returns “John”, and
  • p.firstName returns “Jane”.

However, if we were to modify the return statement for fullName to have the following (instead of outputting the firstName):

const person = { firstName: 'John', lastName: 'Doe', id: 1, fullName() { function name() { return this; } const p = name(); return `${this} ${p}`; }, }; // Outputs [object Object] [object Window] console.log(person.fullName());

You’ll notice that the this returned inside the name() function refers to the object Window, which is a global object. Even though this is used inside an object, it is still seen as being used alone and inside a function. As such, it refers to the global object.

If we want to bind this to any object properties defined inside name(), one way is to assign the this value from the calling object to another variable that would be used inside the nested function.

const person = { firstName: 'John', lastName: 'Doe', id: 1, fullName() { const that = this; function name() { return that; } return name(); }, };

Furthermore, methods such as bind(), call(), and apply() can be used to refer this to any object.

The code below illustrates the use of the bind() method where the member object borrows a property from the person object. In this case, the this keyword refers to the member object, so we get the output “Steve Doe”.

const person = { firstName: 'John', lastName: 'Doe', id: 1, fullName() { return `${this.firstName} ${this.lastName}`; }, }; const member = { firstName: 'Steve', lastName: 'Doe', }; const p = person.fullName.bind(member); // Outputs "Steve Doe" console.log(p());

Get Started With Sentry

Get actionable, code-level insights to resolve JavaScript performance bottlenecks and errors.

  1. Create a free Sentry account

  2. Create a JavaScript project and note your DSN

  3. Grab the Sentry JavaScript SDK

<script src="https://browser.sentry-cdn.com/7.112.2/bundle.min.js"></script>
  1. Configure your DSN
Sentry.init({ dsn: 'https://<key>@sentry.io/<project>' });

Loved by over 4 million developers and more than 90,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.

Share on Twitter
Bookmark this page
Ask a questionJoin the discussion

Related Answers

A better experience for your users. An easier life for your developers.

    TwitterGitHubDribbbleLinkedinDiscord
© 2024 • Sentry is a registered Trademark
of Functional Software, Inc.