What you'll be able to do

By the end of this page you should be able to predict this from how a function is called, explain why a method “loses” this when passed as a bare callback, and know that arrow functions do not get their own this.

Previous post: AbortController with fetch. This opens Phase 9 — mental models.

Who this is for

  • People who logged this and saw undefined or window
  • Beginners whose button handler cannot read this.count
  • Anyone scared of this interviews

You can skip this if call-site rules are solid. Come back when bind is next (#61).

this is not “the function’s owner” by default

In JavaScript, this depends mainly on the call site — how you invoke the function — not where it was written.

Scenario A — method call. user.sayHi()this is user.

Scenario B — plain call. const f = user.sayHi; f()this is usually undefined in strict mode (modules are strict).

Method call

const user = {
  name: "Asha",
  sayHi: function () {
    console.log("Hi, " + this.name);
  },
};
user.sayHi(); // Hi, Asha

Rule: object.method() sets this to object.

Lost this in a callback

const button = document.querySelector("button");
button.addEventListener("click", user.sayHi);
// Inside sayHi, this is often the button (or undefined), not user

Scenario A — DOM handler. The browser calls your function with this = element.

Scenario B — setTimeout. setTimeout(user.sayHi, 0) also loses the method call shape.

Fixes you will use: wrap in arrow () => user.sayHi(), or .bind(user) (next post).

Arrow functions copy this from outside

const user = {
  name: "Asha",
  sayHi: function () {
    const inner = () => console.log(this.name);
    inner();
  },
};
user.sayHi(); // Asha — arrow saw this from sayHi

Scenario A — nested helper inside a method. Arrows keep the method’s this.

Scenario B — arrow as object method. Often wrong for this — prefer function for methods when you want this = object.

A tiny practice file

<!DOCTYPE html>
<html>
  <body>
    <button id="go">Call methods</button>
    <pre id="out"></pre>
    <script>
      const out = document.getElementById("out");
      const user = {
        name: "Asha",
        sayHi: function () {
          out.textContent += "method this.name=" + this.name + "\n";
        },
      };
      document.getElementById("go").addEventListener("click", function () {
        out.textContent = "";
        user.sayHi();
        const loose = user.sayHi;
        try {
          loose();
        } catch (err) {
          out.textContent += "loose call error: " + err.message + "\n";
        }
        document.getElementById("go").addEventListener(
          "click",
          function once() {
            out.textContent += "handler this.id=" + this.id + "\n";
            this.removeEventListener("click", once);
          }
        );
      });
    </script>
  </body>
</html>

Mistakes I see a lot

1. Believing this always means “the object above the function in the file.”

2. Using arrow functions as object methods and expecting this to be the object.

3. Passing obj.method into setTimeout without wrapping/binding.

4. Mixing React class this lore with modern function components — different era; here we stay in plain JS.

What to try before the next post

  1. Call a method with obj.fn() vs const f = obj.fn; f().
  2. Pass a method to addEventListener and log this.
  3. Nest an arrow inside a method; compare to a nested function.

Next in this series: call, apply, and bind — fixing lost this on purpose.

Try this next outside the series

These mental models become more useful when you can point at a real framework problem they explain.