The this Keyword, call(), apply() and bind()

Learn what this refers to in methods, plain functions, arrow functions, event handlers and classes, and control it with call, apply and bind.

Lesson 28 of 56Intermediate16 min read

this is one of the most talked-about words in JavaScript, because its value isn't fixed. Inside a function, this refers to the object the function was called on, and that's decided at the moment of the call, not when the function is written. The same function can see a different this each time it runs.

Most of the time it does what you'd expect. In user.greet(), this is user. Problems start when a method is passed somewhere else, for example as a callback to setTimeout or addEventListener. The function gets called without its object, this is lost, and you see errors like "Cannot read properties of undefined".

In this lesson you'll learn the simple rules that decide this, why arrow functions behave differently, and how the three function methods call(), apply() and bind() let you choose this yourself. These ideas matter for objects, classes and event handling, and they're another interview favourite.

The rules for this

How the function is calledthis is…
As a method: obj.method()obj, the object before the dot
As a plain function: fn()undefined in strict mode and modules, window otherwise
With new: new User()The newly created object
With call, apply or bindWhatever you pass as the first argument
As a DOM event handler (normal function)The element the listener is attached to
Arrow functionNot its own: it uses this from the surrounding code

The quick test: look at the call, not the definition. Whatever is to the left of the dot when the function is called is usually this.

Losing this

JavaScript
const timer = {
  seconds: 10,
  report() { console.log(this.seconds); },
};

timer.report();             // 10
const fn = timer.report;
fn();                       // undefined: called without an object
setTimeout(timer.report, 0); // same problem

Copying a method into a variable or passing it as a callback separates it from its object. When it's later called as a plain function, this is no longer timer. This is the single most common this bug.

Arrow functions and this

Arrow functions don't have their own this. They use the this of the code around them, fixed when they're created. That makes them perfect for callbacks inside methods:

JavaScript
const counter = {
  count: 0,
  start() {
    setInterval(() => {
      this.count++; // this is still counter
    }, 1000);
  },
};

But it also means you shouldn't use an arrow function as a method: { name: "A", hi: () => this.name } won't see the object, because there's no surrounding method to borrow this from.

call, apply and bind

MethodWhat it doesExample
fn.call(obj, a, b)Calls fn now with this = obj, arguments listedgreet.call(user, "Hi")
fn.apply(obj, [a, b])Calls fn now, arguments in an arrayMath.max.apply(null, nums)
fn.bind(obj, a)Returns a new function with this fixed to objconst report = timer.report.bind(timer)

bind is the one you'll use most, because it fixes the lost-this problem for callbacks: setTimeout(timer.report.bind(timer), 0). Nowadays apply is rarely needed, since the spread syntax Math.max(...nums) does the same job.

JavaScript this Keyword Syntax

this, call, apply and bind

const user = { name: "Ana", hi() { return `Hi, ${this.name}`; } };
user.hi();                         // "Hi, Ana"

function intro(greeting) { return `${greeting}, ${this.name}`; }
intro.call(user, "Hello");         // "Hello, Ana"
intro.apply(user, ["Hey"]);        // "Hey, Ana"
const bound = intro.bind(user);
bound("Hiya");                     // "Hiya, Ana"

JavaScript this Keyword Summary

  • this is decided by how a function is called, not where it's written.
  • In obj.method(), this is obj; in a plain call it's undefined in strict mode.
  • Passing a method as a callback loses this.
  • Arrow functions take this from the surrounding code, so use them for callbacks inside methods.
  • call and apply run a function with a chosen this; bind returns a new function with this fixed.

JavaScript this Keyword Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Methods and lost this

const player = {
  name: "Kai",
  score: 40,
  describe() {
    return `${this?.name} has ${this?.score} points`;
  },
};

console.log(player.describe());

const loose = player.describe;
console.log("Lost this:", loose());

const fixed = player.describe.bind(player);
console.log("Bound:", fixed());
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 4 to 5this refers to whatever object the method is called on.
  2. Line 9Called on player, so this is player.
  3. Lines 11 to 12Called on its own, this is no longer player (it's undefined in strict mode, or the global window otherwise), so the score is missing.
  4. Lines 14 to 15bind creates a version where this is always player.
Example 2

Arrow functions inside methods

const quiz = {
  title: "Capitals",
  questions: ["France", "Japan", "Peru"],

  listWithArrow() {
    return this.questions.map(q => `${this.title}: ${q}`);
  },

  listWithFunction() {
    return this.questions.map(function (q) {
      return `${this?.title}: ${q}`;
    });
  },
};

console.log(quiz.listWithArrow());
console.log(quiz.listWithFunction());
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 6The arrow function borrows this from listWithArrow, so it sees quiz.
  2. Lines 10 to 12A normal function callback gets its own this, which is not quiz, so the title is lost.
Example 3

call, apply and borrowing methods

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

const ana = { name: "Ana" };
const ben = { name: "Ben" };

console.log(introduce.call(ana, "Hello", "!"));
console.log(introduce.apply(ben, ["Hi", "."]));

const sayHiAsAna = introduce.bind(ana, "Hi");
console.log(sayHiAsAna("?"));

const scores = [12, 48, 7];
console.log(Math.max.apply(null, scores), Math.max(...scores));
ConsoleEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 8call sets this to ana and lists the arguments.
  2. Line 9apply is the same but takes an array of arguments.
  3. Line 11bind fixes this and the first argument, returning a new function.
  4. Line 15apply used to be the way to pass an array to Math.max; spread does it now.

Common JavaScript this Keyword Mistakes

Arrow function as a method

Don't
const cart = {
  items: 3,
  count: () => this.items, // this is not cart
};
Do
const cart = {
  items: 3,
  count() { return this.items; },
};

Passing a method as a callback

Don't
button.addEventListener("click", menu.toggle); // this is the button, not menu
Do
button.addEventListener("click", () => menu.toggle());
// or
button.addEventListener("click", menu.toggle.bind(menu));

Calling bind and expecting it to run

Don't
report.bind(timer); // returns a new function, nothing happens
Do
report.call(timer);           // run now
const later = report.bind(timer); later(); // run later

JavaScript this Keyword in Real Projects

this in real code

Class-based code, including older React components, binds methods in the constructor or uses arrow functions in class fields to keep this. jQuery handlers rely on this being the element. Libraries use call and apply to run your callbacks with a particular context. Most modern code avoids the problem by using arrow functions for callbacks and event.currentTarget in handlers.

JavaScript this Keyword Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Create a version of show with this fixed to item.

const item = { name: "Lamp" };
function show() { return this.name; }
const showItem = show.(item);
console.log(showItem());
Predict the outputmedium

What is logged?

const a = { n: 1, get() { return this.n; } };
const b = { n: 2 };
b.get = a.get;
console.log(a.get(), b.get());
Multiple choiceeasy

In user.save(), what is this inside save?

Multiple choicemedium

What's the difference between call and bind?

Fix the bugmedium

stopwatch.start() should increase seconds by 1 every 50ms, and getLabel (a copy of the method) should still return the right label. Fix the this problems.

const stopwatch = {
  seconds: 0,
  label() { return `${this.seconds}s`; },
  start() {
    this.id = setInterval(function () {
      this.seconds++;
    }, 50);
  },
};
stopwatch.start();
const getLabel = stopwatch.label;
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • Seconds increase
  • The copied method keeps this

JavaScript this Keyword Quiz

5 questions to check what you learned.

  1. When is the value of this decided for a normal function?

    • When the function is written
    • When the page loads
    • It never changes
    • When the function is called
  2. Do arrow functions have their own this?

    • No, they use this from the surrounding code
    • Yes, always the window
    • Yes, the arrow itself
    • Only in classes
  3. Which method takes arguments as an array?

    • call
    • apply
    • bind
    • map
  4. In a normal function event listener, what is this?

    • The event object
    • The window, always
    • The element the listener is attached to
    • undefined
  5. What is this inside a plain function call in strict mode?

    • window
    • The function itself
    • null
    • undefined

JavaScript this Keyword Challenge

A bank account that keeps this

Create an object account with:

  1. owner: "Sam" and balance: 0
  2. A method deposit(amount) that adds to this.balance and returns the new balance
  3. A method depositLater(amount, ms) that calls this.deposit(amount) after ms milliseconds using setTimeout with an arrow function
  4. A variable quickDeposit that is account.deposit bound to account
ConsoleEdit the code, then press Run or Ctrl+Enter
Checks
  • deposit adds to the balance
  • bound copy keeps this
  • depositLater works after a delay
  • Uses bind and an arrow function