CodeMIRAI
0 XP

The this keyword

4 min read 7 runnable examples Quiz included

this is a special word available inside functions. Most of the time it means "the object the function was called on", which lets one method work for whichever object it belongs to. It is also one of the most confusing parts of JavaScript, because its value is decided when the function is called, not where the function is written. This lesson goes through every case.

this in a method

When you call a function as a method, with object.method(), this inside it is the object before the dot:

JavaScript
const asha = {
  name: "Asha",
  greet() {
    return `Hi, I'm ${this.name}`;
  },
};
const leo = { name: "Leo", greet: asha.greet };   // the SAME function

console.log(asha.greet());   // this is asha
console.log(leo.greet());    // this is leo

One function, two answers: this follows the object in front of the dot at the moment of the call. That's what makes methods reusable.

The rule: how it's called, not where it's written

How the function is calledthis is
obj.method()obj
method(), a plain callundefined in strict mode and modules (the global object in old sloppy scripts)
new Thing()the new object being built
fn.call(obj), fn.apply(obj), fn.bind(obj)()obj, chosen by you
an arrow functionthe this of the code around it (arrows have none of their own)
an event listener (a regular function)the element the listener is on

Losing this

The most common this bug: taking a method out of its object and calling it on its own. The dot is gone, so this is no longer the object:

JavaScript
"use strict";
const counter = {
  count: 0,
  increment() {
    this.count++;
    return this.count;
  },
};

console.log(counter.increment());     // called with a dot: works

const inc = counter.increment;        // the function, without its object
try {
  inc();                              // a plain call: this is undefined
} catch (err) {
  console.log(err.name + ":", err.message);
}

"use strict"; as the first line switches on strict mode, which makes a plain call's this undefined (classes and modules are always strict). Without it, old-style "sloppy" code gets the global object instead, which hides the mistake. Either way, the method has lost its object.

This happens whenever a method is passed as a callback: setTimeout(counter.increment, 1000) or button.addEventListener("click", counter.increment) both call the function later without the dot.

Fixing it: bind, arrow functions

bind makes a copy of the function with this fixed to the object you choose, however it's called later:

JavaScript
const counter = {
  count: 0,
  increment() {
    this.count++;
    return this.count;
  },
};

const inc = counter.increment.bind(counter);
inc();
inc();
console.log(inc(), counter.count);

// a callback that keeps its this: wrap the call in an arrow function
const later = () => counter.increment();
console.log(later());

Wrapping the call in an arrow, () => counter.increment(), works too, because the call inside still has its dot.

Arrow functions take this from outside

Arrow functions have no this of their own: inside one, this is whatever it was in the surrounding code. That is exactly what you want for a callback inside a method:

JavaScript
"use strict";
const team = {
  name: "Rockets",
  players: ["Asha", "Leo"],
  roster() {
    // the arrow uses roster's this, the team object
    return this.players.map((p) => `${p} plays for ${this.name}`);
  },
  rosterBroken() {
    // a regular function gets its own this (undefined here)
    return this.players.map(function (p) {
      return `${p} plays for ${this?.name}`;
    });
  },
};
console.log(team.roster());
console.log(team.rosterBroken());

And it's exactly what you don't want for the method itself: greet: () => this.name would not see the object. Rule of thumb: regular method syntax for methods, arrows for callbacks inside them.

call and apply

call and apply call a function once, with this set to the first argument. They differ only in how the other arguments are passed:

JavaScript
function introduce(greeting, punctuation) {
  return `${greeting}, I'm ${this.name}${punctuation}`;
}
const mei = { name: "Mei" };

console.log(introduce.call(mei, "Hello", "!"));      // arguments one by one
console.log(introduce.apply(mei, ["Hey", "."]));     // arguments as an array
const meiIntro = introduce.bind(mei, "Hi");          // bind can fix arguments too
console.log(meiIntro("?"));
MethodCalls the functionArgumentsReturns
fn.call(obj, a, b)nowone by onethe function's result
fn.apply(obj, [a, b])nowas an arraythe function's result
fn.bind(obj, a)later, when you call the resultfixed now, more latera new function

this in classes

In a class, this inside a method is the instance (the object made with new). Class bodies run in strict mode, so a method that loses its object gets undefined, and the same fixes apply:

JavaScript
class Timer {
  constructor(label) {
    this.label = label;
    this.ticks = 0;
  }
  tick() {
    this.ticks++;
    return `${this.label}: ${this.ticks}`;
  }
}
const t = new Timer("egg");
console.log(t.tick(), t.tick());

const loose = t.tick;
try {
  loose();
} catch (err) {
  console.log("lost this:", err.message);
}
const bound = t.tick.bind(t);
console.log(bound());

The classes lesson covers classes in full.

this in event listeners

In the browser, a regular function used as an event listener gets the element as this. An arrow function doesn't, so use event.currentTarget instead, which works with both:

HTML
<button id="b1">Regular function</button>
<button id="b2">Arrow function</button>
<p id="out"></p>
<script>
  const out = document.getElementById("out");
  document.getElementById("b1").addEventListener("click", function (event) {
    out.textContent = "this is the <" + this.tagName.toLowerCase() + "> with id " + this.id;
  });
  document.getElementById("b2").addEventListener("click", (event) => {
    out.textContent = "arrow: use event.currentTarget, id " + event.currentTarget.id;
  });
</script>

Key points

  • this is decided by how a function is called: obj.method() makes this the object.
  • Taking a method out of its object (as a callback) loses this.
  • bind fixes this permanently; call and apply set it for one call.
  • Arrow functions have no own this: they use the surrounding one, which suits callbacks inside methods.
  • Use regular method syntax for methods; use event.currentTarget in listeners.

Practice

  1. Make an object car with brand and a method describe() that returns a sentence using this.brand. Copy the method onto another object and call it there.
  2. Show the "lost this" bug with const d = car.describe; d();, then fix it with bind.
  3. In an object with an array items and a name, write a method that uses map and an arrow to return "<item> from <name>" for each item.
  4. Use call to run a function function total(tax) { return this.price * (1 + tax); } on { price: 100 } with a tax of 0.18.
Finished this lesson?Mark it complete to earn +20 XP and move your progress on.