Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 6

this and Function Binding

Prerequisites: you should be comfortable with function declarations, arrow functions, object literals, and lexical scope from earlier chapters.
Level: AdvancedLength: Mid2 min read

Read at another depth

this and Function Binding

Prerequisites: you should be comfortable with function declarations, arrow functions, object literals, and lexical scope from earlier chapters.

this is not defined by where a function is written but by how it is called. Four binding rules apply, in priority order:

  1. new binding: a function invoked with new gets this set to a freshly created object.
  2. explicit binding: call, apply, or bind set this to the first argument.
  3. implicit binding: obj.method() binds this to obj.
  4. default binding: a bare call gets this as undefined (strict mode) or the global object (sloppy mode).

Arrows are the exception: they have no this at all and inherit it lexically from the enclosing scope. call, apply, and bind on an arrow are silently ignored with respect to this.

Code example in javascript
'use strict';
function shout() { return this && this.tag || 'no context'; }

const obj = { tag: 'obj', shout, arrow: () => 'arrow: ' + (this === undefined) };

shout();                       // 'no context' (default binding)
obj.shout();                   // 'obj'       (implicit binding)
shout.call({ tag: 'called' }); // 'called'    (explicit binding)

Where bindings break

The classic bug: extracting a method or passing it as a callback detaches it from its receiver.

Code example in javascript
const timer = {
  label: 'timer',
  run() {
    setTimeout(function () {
      console.log(this.label); // undefined: default binding inside callback
    }, 10);
    setTimeout(() => {
      console.log(this.label); // 'timer': arrow inherits this from run()
    }, 20);
  },
};
timer.run();

The non-arrow callback loses its receiver at the call site; the arrow never had one to lose.

bind, call, apply

  • call(thisArg, a, b) — invoke now, arguments listed individually.
  • apply(thisArg, [a, b]) — invoke now, arguments as an array.
  • bind(thisArg) — return a new function permanently bound (a "hard binding").

A bound function's binding is final: further call on it cannot override this. Note also that bind is partial application of the leading arguments, a technique worth knowing in its own right.

Code example in javascript
const bound = shout.bind({ tag: 'hard' });
bound.call({ tag: 'soft' }); // 'hard' — bind wins

Class internals

Inside a class constructor, this is the new instance. Methods live on Class.prototype, so this resolves through the prototype chain at call time. This is why the same detachment problem affects class methods — and why React class components historically bound handlers in constructors, before arrow class fields became idiomatic.

diagram mermaid caption: How this is resolved for a given call alt: Flowchart starting from a call site: if new was used, this is the new object; else if call, apply, or bind was used, this is the provided argument; else if called as obj.method, this is obj; else if the function is an arrow, this comes from the enclosing scope; otherwise default binding applies, undefined in strict mode.

Code example in text
flowchart TD
    A[Call site] --> B{new?}
    B -- yes --> C[this = new object]
    B -- no --> D{call / apply / bind?}
    D -- yes --> E[this = first argument]
    D -- no --> F{obj.method()?}
    F -- yes --> G[this = obj]
    F -- no --> H{arrow function?}
    H -- yes --> I[this = enclosing lexical this]
    H -- no --> J[default: undefined strict / global sloppy]

Gotchas

  • Arrow methods defined as class fields share one this per instance but avoid detachment; prototype methods do not. Choose based on whether the method is passed around.
  • this in top-level module code is undefined under ES modules, regardless of strict mode.
  • Debugging detachment is easier if you ask "who is on the left of the dot at the call site?" — for detached calls, nobody.

Exercise

Why does const f = obj.method; f(); lose the receiver, and give two ways to fix it?

Show answer

Assigning the method to f and calling it bare applies default binding, so this is not obj. Fix by wrapping: f = () => obj.method() (restores implicit binding), or by making the method an arrow-bound field, or f = obj.method.bind(obj).

Spotted a mistake, or code that does not work?

Report an issue

Chapter: this and Function Binding

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that