Question

JavaScript this Keyword: How It Works and When to Use It

Question

How does the JavaScript this keyword work, and when should it be used?

I am looking for a clear explanation of what this does and how to use it correctly. It sometimes appears to behave unexpectedly, and I do not understand why. How is the value of this determined, and when is it appropriate to use it?

Short Answer

By the end of this page, you will know that JavaScript this is usually determined by how a function is called, not where the function was written. You will be able to use this in object methods and classes, avoid common callback problems, and choose between regular functions and arrow functions.

Concept

this is a special JavaScript value available inside many functions. It usually refers to the object associated with the current function call.

The most important rule is:

For a regular function, this is determined by the call site: the code that calls the function.

For example, when user.greet() is called, this inside greet is user:

const user = {
  name: "Ava",
  greet() {
    return `Hello, ${this.name}!`;
  }
};

console.log(user.greet()); // Hello, Ava!

Here, this.name means user.name because user is the object before the dot in user.greet().

this is useful when code needs to work with the particular object that received a method call. Instead of writing separate functions for every user, product, or account, one method can refer to the current instance through this.

Arrow functions are the major exception. An arrow function does not create its own this; it captures this from the surrounding code.

Mental Model

Think of a regular function as an employee who looks at who handed it the current task.

  • In car.start(), the employee sees that car handed over the task, so this means car.
  • In bike.start(), the same function can see that bike handed over the task, so this means bike.
  • If the function is called by itself, such as start(), nobody is identified as the caller. In strict mode, this is undefined.

An arrow function is different: it is like an employee who always follows the instructions of the office where they were hired. It keeps the surrounding this rather than receiving a new one from its caller.

Take Quiz

Syntax and Examples

A method can use this to access properties on the object that called it:

const counter = {
  count: 0,

  increment() {
    this.count += 1;
    return this.count;
  }
};

console.log(counter.increment()); // 1
console.log(counter.increment()); // 2

this.count refers to counter.count because increment was called as counter.increment().

The same reusable function can behave differently for different objects:

function describe() {
  return `${this.brand} ${this.model}`;
}

const phone = { brand: "Orion", model: "X1", describe };
const laptop = { brand: "Northstar", model: "Pro", describe };

console.log(phone.describe());  // Orion X1
console.log(laptop.describe()); // Northstar Pro

In classes, this normally means the instance created with new:

class BankAccount {
  constructor(owner, balance) {
    this.owner = owner;
    this.balance = balance;
  }

  deposit(amount) {
    this.balance += amount;
  }
}

const account = new BankAccount("Mina", 100);
account.deposit(25);
console.log(account.balance); // 125

Use this when a method must read or change data belonging to its current object or class instance.

Step by Step Execution

Consider this example:

const playlist = {
  name: "Morning Focus",
  songs: 12,

  addSong() {
    this.songs += 1;
    console.log(`${this.name}: ${this.songs} songs`);
  }
};

playlist.addSong();

Execution trace:

  1. JavaScript creates the playlist object with name, songs, and addSong.
  2. playlist.addSong() calls the addSong method through playlist.
  3. Because playlist is before the dot, this inside addSong is playlist.
  4. this.songs reads playlist.songs, which is initially 12.
  5. The method adds 1, so playlist.songs becomes 13.
  6. this.name reads playlist.name, which is "Morning Focus".
  7. The console prints Morning Focus: 13 songs.

Now compare a detached method:

const add = playlist.addSong;
add();

add() is not called as playlist.addSong(). It is called as a plain function. In modern JavaScript modules and strict mode, this is undefined, so accessing this.songs throws an error.

Real World Use Cases

this commonly appears in these situations:

  • Class instances: A ShoppingCart instance uses this.items and this.total to manage its own state.
  • Object methods: A configuration object uses this to read related settings.
  • UI event handlers: In a regular browser event listener, this can refer to the element receiving the event. event.currentTarget is often clearer and more reliable.
  • Reusable methods: One function can operate on multiple compatible objects when called as their method.
  • Framework and library code: Some older APIs and class-based code use this to refer to a component or instance.

Example: a simple cart class:

class ShoppingCart {
  constructor() {
    this.items = [];
  }

  addItem(item) {
    this.items.push(item);
  }

  itemCount() {
    return this.items.length;
  }
}

Each cart has its own items array because this refers to the specific cart instance.

Take Quiz

Real Codebase Usage

In production code, developers use this mostly in methods and classes, while avoiding unclear or accidental bindings.

Use methods for object-owned behavior

const session = {
  userId: null,

  isAuthenticated() {
    return this.userId !== null;
  }
};

Use guard clauses with instance state

class FileUploader {
  constructor(file) {
    this.file = file;
  }

  upload() {
    if (!this.file) {
      throw new Error("A file is required.");
    }

    return `Uploading ${this.file.name}`;
  }
}

Preserve this in callbacks when necessary

A common pattern is an arrow callback inside a class method. The arrow captures the method's this:

class Timer {
  constructor() {
    this.seconds = 0;
  }

  start() {
    setInterval(() => {
      this.seconds += 1;
    }, 1000);
  }
}

Alternatively, bind a regular method once, often in a constructor:

class SearchController {
  constructor() {
    this.query = "";
    this.handleInput = this.handleInput.bind(this);
  }

  handleInput(event) {
    this.query = event.target.value;
  }
}

In modern JavaScript, prefer plain functions and explicit parameters when no object-specific state is needed. This reduces unnecessary dependence on this.

Common Mistakes

Losing this by separating a method from its object

"use strict";

const user = {
  name: "Ava",
  greet() {
    console.log(this.name);
  }
};

const greet = user.greet;
greet(); // TypeError: Cannot read properties of undefined

greet() is a plain function call, so it has no object receiver. Call user.greet() instead, or bind the method:

const greet = user.greet.bind(user);
greet(); // Ava

Using an arrow function as an object method when dynamic this is needed

const user = {
  name: "Ava",
  greet: () => console.log(this.name)
};

user.greet(); // Does not use user as this

The arrow function inherits this from outside the object literal. Use method syntax instead:

const user = {
  name: "Ava",
  greet() {
    console.log(this.name);
  }
};

Forgetting new with a class

class User {
  constructor(name) {
    this.name = name;
  }
}

const user = User("Ava"); // TypeError

Classes must be called with new:

const user = new User("Ava");

Assuming this means the function itself

this is not the function. It is a value supplied by the call style, or inherited lexically by an arrow function.

Relying on top-level this

Top-level this differs between browsers, scripts, modules, and Node.js environments. Do not use it as a reliable global reference. Use globalThis when you specifically need the global object.

Comparisons

SituationWhat this isExample
Object method callThe object before .user.greet() → this is user
Class instance methodThe instance before .account.deposit() → this is account
Constructor call with newThe newly created instancenew User("Ava")
Plain regular function in strict modeundefinedshow()
Arrow functionInherited from surrounding scope() => this.value
call, apply, or bindExplicitly chosen objectshow.call(user)

Regular functions vs arrow functions

FeatureRegular functionArrow function
Gets this from its call siteYesNo
Good for object/class methods needing dynamic thisYesUsually no
Good for callbacks that should keep surrounding thisSometimes, with .bind()Yes
Can be used with newYes, if constructableNo

call, apply, and bind

All three can control this for a regular function:

function introduce(greeting) {
  return `${greeting}, I am ${this.name}.`;
}

const person = { name: "Leo" };

console.log(introduce.call(person, "Hello"));
console.log(introduce.apply(person, ["Hi"]));

const introduceLeo = introduce.bind(person);
console.log(introduceLeo("Welcome"));
  • call invokes immediately with individual arguments.
  • apply invokes immediately with arguments in an array.
  • bind returns a new function whose this is fixed.
Take Quiz

Cheat Sheet

  • this is a special value available in regular functions and methods.
  • For regular functions, inspect how the function is called.
  • object.method() means this is usually object.
  • new Constructor() means this is the new instance.
  • functionName() in strict mode means this is undefined.
  • Arrow functions do not get their own this; they capture the surrounding one.
  • Use method shorthand when an object method needs this:
const object = {
  value: 1,
  getValue() {
    return this.value;
  }
};
  • Use arrow callbacks to retain a surrounding method's this:
setTimeout(() => this.save(), 1000);
  • Use fn.bind(object) when passing a regular method as a callback.
  • Prefer explicit function parameters over this when the function does not represent object-owned behavior.
  • Avoid depending on top-level this; use globalThis for the global object.

FAQ

Is this the same as the current object in JavaScript?

Often, but not always. In object.method(), it is usually the object. In a plain function call, it is undefined in strict mode. Arrow functions inherit it from their surrounding scope.

Why is this undefined in my JavaScript function?

The function was likely called without an object receiver, such as fn() rather than object.fn(), and strict mode is active.

Should I use an arrow function for an object method?

Usually no if the method needs this to refer to the object. Use method syntax or a regular function. Arrow functions are useful for callbacks that should retain the surrounding this.

How do I keep this in a callback?

Use an arrow callback, such as setTimeout(() => this.run(), 0), or bind a regular method with this.run = this.run.bind(this).

What does this mean in a class constructor?

It refers to the new instance being created. Assignments like this.name = name store data on that instance.

What is the difference between call, apply, and bind?

call and apply invoke a function immediately with a chosen this. call takes separate arguments; apply takes an argument array. bind returns a new function with a fixed this.

Do JavaScript modules have a global this?

No. At the top level of an ES module, this is undefined. Use globalThis if you need the global object.

Take Quiz

Mini Project

Description

Build a small TaskList class that keeps a list of tasks. The project demonstrates how this lets each class instance manage its own data through instance methods.

Goal

Create two independent task lists and use this to add tasks, complete tasks, and display each list's summary.

Requirements

  • Create a TaskList class with a name and an empty task list.
  • Add an addTask method that stores a task with a done status.
  • Add a completeTask method that marks a task as complete by its index.
  • Add a summary method that returns the list name and completion count.
  • Create two separate TaskList instances to confirm that their data remains independent.
Take Quiz

Keep learning

Related questions

View more