Skip to content
Lesson 7 of 15

Step 1 of 7 · Reading · ~4 min

Learn

Objects in Depth

this and Methods

Inside a function, this is an extra hidden argument, and which value it gets depends on how the function is called, not where it was written. By the end of this lesson you can name the four ways this gets its value, say why arrow functions are the exception, and fix the "lost this" bug.

The surprise

javascript

Both calls run the same function. const detached = account.summary copies a reference to the function, not a link to account. Called bare, nothing is to the left of the dot, so this is no longer the account. In a plain script this falls back to the global object, which has no holder, giving undefined. In strict mode (and always inside an ES module) it is undefined itself, and reading this.holder throws a TypeError.

The four rules

When a regular function is called, look at the call site:

  1. Method call, obj.fn(): this is the object left of the dot (account above).
  2. Plain call, fn(): this is the global object (sloppy mode) or undefined (strict mode).
  3. new call, new Fn(): this is a fresh empty object that new creates and returns. Forgetting new is rule 2 in disguise: the assignments land on the global object.
  4. Explicit, via call, apply or bind: this is whatever you pass.
javascript

bind also presets leading arguments: const add10 = ((a, b) => a + b).bind(null, 10); makes add10(5) return 15.

Arrow functions have no this of their own

An arrow function does not take part in the four rules. Its this is whatever this was where the arrow was written, like any other captured variable. That makes arrows ideal for callbacks inside methods:

javascript

report is called as a method, so this is timer, and the arrow inherits it. In broken the callback is a regular function called plainly by map, so its this is the global object. The flip side: an arrow is the wrong choice for an object's own method, because { greet: () => this.name } takes this from the surrounding scope, not from the object.

Losing this, and the three fixes

Passing a method somewhere that will call it later (setTimeout, an event handler, array.map) detaches it, exactly like detached above. Strict mode makes it loud:

javascript

Fixes: bind at the hand-off (job.run.bind(job)), wrap in an arrow (() => job.run()), or avoid this altogether by keeping the data in a closure, as in the closures lesson.

Common mistakes

  • Extracting a method and calling it bare: const { run } = job;.
  • Using function for a callback inside a method and expecting the outer this.
  • Using an arrow function as an object method that needs this.
  • Forgetting new, which silently writes properties onto the global object.
  • Trying to re-bind a bound function with call. It has no effect.
  • Writing fn().bind(x): that calls fn first. The .bind goes on the function itself.

Your exercise

You have just seen what bind returns; now write one. The usual slip is using the this of the wrapper you return instead of the thisArg you were given.

Up nextThe Prototype ChainObjects in Depth

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…