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 7

this and Function Binding

Prerequisites: you are comfortable with function declarations vs expressions, closures, and the call stack. You already know `this` exists and roughly that "it depends on how the function is called." This chapter gives you the full binding model, the failure modes, and the decision criteria for choo
Level: AdvancedLength: In depth4 min read

Read at another depth

this and Function Binding

Prerequisites: you are comfortable with function declarations vs expressions, closures, and the call stack. You already know this exists and roughly that "it depends on how the function is called." This chapter gives you the full binding model, the failure modes, and the decision criteria for choosing between arrows, bind, and explicit invocation.

The Four Binding Rules

this is not a property of the function itself. It is a hidden argument supplied at call time, resolved by the first matching rule below.

  1. New binding: new f() — this is the freshly created object.
  2. Explicit binding: f.call(x), f.apply(x), f.bind(x) — this is x (except when hard-bound; see below).
  3. Implicit binding: obj.f() — this is obj, the receiver to the left of the dot at the call site.
  4. Default binding: a bare call f() — this is undefined in strict mode, globalThis in sloppy mode.

Rules are checked in that order. Notably, new beats explicit binding for ordinary functions, but a hard-bound function ignores both new and further calls — bind is a one-way commitment. Only the explicit this argument of bound functions is locked; arguments passed to bind after the first are partially applied and prepend to later calls.

Code example in javascript
'use strict';
function show(...args) {
  return [this, ...args];
}

const bound = show.bind('LOCKED', 1);

console.log(bound());            // ['LOCKED', 1]
console.log(bound.call('other', 2)); // ['LOCKED', 1, 2] — this ignored
console.log(new (show.bind('x'))()); // {} — new wins only via this-barrier semantics

The receiver is determined lexically at the call site, which is why method extraction breaks:

Code example in javascript
const counter = {
  n: 0,
  inc() { this.n += 1; return this.n; },
};

counter.inc();        // 1 — implicit binding
const inc = counter.inc;
inc();                // TypeError: Cannot set properties of undefined

Only the last property before the call matters: a.b.c.f() binds this to c.

Resolution order diagram

Arrow Functions: Lexical this

Arrow functions have no this binding of their own. A reference to this inside an arrow is an ordinary closure variable, resolved lexically to the enclosing function's this. Consequently:

  • call, apply, and bind cannot change an arrow's this; their first argument is silently ignored (though bind still partially applies arguments).
  • Arrows cannot be used as constructors.
  • Arrows have no arguments object; use rest parameters.

This makes arrows the right tool when you want to delegate to the surrounding this, and the wrong tool when a function will ever be called as a method or constructor.

Code example in javascript
const timer = {
  seconds: 0,
  start() {
    setInterval(() => {
      this.seconds += 1; // lexical this: timer
    }, 1000);
  },
};

Where arrows bite back

  • Prototype/class methods defined as arrows on instances: each instance gets its own function; super inside an arrow refers to the enclosing class's home, which can produce surprising super references in object literals.
  • Event handlers: DOM event handlers are invoked with the element as receiver. An arrow captures the defining this instead, which is either what you wanted (a closure) or a bug (you needed event.currentTarget).
  • Object literals: this in a shorthand arrow property resolves to the enclosing scope's this, not the object — often undefined at module scope.

Internal Mechanics and Edge Cases

  • super.method() inside a class performs a dynamic this-based dispatch but a static home-object lookup for the prototype. You cannot replicate it with Object.getPrototypeOf(this).method.call(this) in subclasses that override the method — it would recurse.
  • Function.prototype.bind polyfill limitations: a native bound function preserves arity (length) up to the bound arguments, has a name prefixed with bound , and is exotic — it cannot be re-bound and forwards new correctly to the target. Polyfilled versions historically failed new.
  • Reflect.apply(f, thisArg, args) is the clean primitive; f.apply(thisArg, args) differs only in that apply can be shadowed or detached from the function.
  • Callbacks in class fields: class field arrow functions (handleClick = () => {...}) bind at construction time, one closure per instance — a memory and equality trade-off vs. a bound prototype method created once per class.
  • Sloppy-mode default this = globalThis is a boxing hazard historically (primitives as this were boxed in sloppy mode); strict mode passes this through uncoerced. Always run modules (which are strict) or add 'use strict'.
  • this in top-level module code is undefined; in a classic script it is globalThis.

Decision Criteria

SituationUseWhy
Inner callback needing outer `this`Arrow functionLexical capture, no per-call allocation
Method to be detached/reused`bind` or class-field arrowPre-commit the receiver
Borrowing a method once`call` / `Reflect.apply`No retained closure
Function used with `new`Ordinary function/classArrows throw
Generic utility ignoring receiverArrow or `() =>` at module scopeAvoid accidental implicit binding

Failure modes to watch: double-binding (.bind() on an already-bound function does nothing to this — debug by checking fn.name for the bound prefix); lost receivers through destructured method references (const { log } = console works because log ignores this, but const { push } = arr throws); and React-style "bound in constructor vs. class-field arrow vs. inline arrow at JSX call site" — the inline arrow re-allocates per render, which matters for memoized children.

Exercise

Why does const inc = counter.inc; inc() lose this, while counter.inc() works, even though both invoke the same function object?

Show answer

this is chosen at call time from the call-site syntax. In counter.inc() the receiver is counter (implicit binding). In inc() there is no receiver, so default binding applies — undefined under strict mode. The function object itself never stores this.

Exercise

What does f.bind(a).call(b) log if f logs this? What about f.call(a).bind — why is that expression invalid, and what is the correct chained form?

Show answer

f.bind(a).call(b) logs a — hard binding locks this, later call arguments to this are ignored. f.call(a).bind is invalid because f.call(a) invokes f and its return value is whatever f returns, not a function; to partially apply you must bind before calling: f.bind(a, ...presetArgs).

Exercise

You replace setInterval(function () { this.tick(); }, 1000) inside a method with an arrow and it works. Name one context where the same substitution silently breaks behavior.

Show answer

When the function is used as a DOM event handler or instance method that must receive the caller as receiver — e.g. element.addEventListener('click', ...) where you need the element. The arrow's lexical this is the defining object, not the event target; you'd need event.currentTarget.

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