JavaScript course Lesson 5 of 6

JavaScript from zero: a method needs its object

Pulling a method off the object and calling it loses this. The detached call throws. Calling label on the latte prints latte $4.50.

Zoe is one of GoByte's characters. This post was drafted by AI agents in Zoe's voice, then fact checked, run and edited by the GoByte team.

Back to top

latte.label() sets this to the latte. If you copy the method into a bare name and call that name, this is not the drink. Inside a class, that call throws TypeError. The tip: call the method on the object, or bind it on purpose.

A method call sets this. A bare call does not#

latte.label reads the function off the object without calling it. The value in label is the function alone. Calling label() supplies no receiver. Class bodies run in strict mode, so this is undefined and reading this.name throws. The catch stores the word lost. latte.label() is the call that sets this, and it still prints latte $4.50. If you must pass the function, pass latte.label.bind(latte), or pass the object and let the callee call the method.

The function lost the object
  1. label()no receiverlost
class Item {
  constructor(name, cents) {
    this.name = name;
    this.cents = cents;
  }

  label() {
    const frac = String(this.cents % 100).padStart(2, "0");
    return this.name + " $" + Math.floor(this.cents / 100) + "." + frac;
  }
}

const latte = new Item("latte", 450);
const label = latte.label;
let detached;
try {
  detached = label();
} catch (e) {
  detached = "lost";
}
console.log(detached);
console.log(latte.label());
lost
latte $4.50

The dot at the call is what sets this#

const label = latte.label takes the function and drops the drink. label() runs it with no object. Reading this.name then throws, the catch stores "lost", and the first line prints lost. latte.label() still works. The method was never broken. The call was.

This shows up when you pass a method as a callback: button.addEventListener("click", latte.label) calls label later, without the drink. Pass () => latte.label() instead, so the call still has the dot. Or use latte.label.bind(latte), which returns a function whose this is fixed.

Catch it only to show the failure#

The try is here so the lesson can print both outcomes. In a program, do not wrap every method call. Call it on the object. If a callback must hold the function, wrap the call in an arrow so this stays put. The next lesson passes the whole object into a function, which avoids peeling the method off in the first place.

Report a mistake

Your product here? Partner with us

Back to top

Discussion

No comments yet. Signed in GoByte members with a verified e-mail can join. Community guidelines

Reading is open to everyone. Commenting and voting need a GoByte account with a verified e-mail.