this, call, apply & bind

Medium100% Free~20 mins#this#call#apply#bind#arrow-functions#context#lexical-this
Key Learning Objectives
âś“

Master the 4 core binding rules of JavaScript 'this': default, implicit, explicit, and new.

âś“

Understand why extracting an object method loses implicit context (the unbound function trap).

âś“

Grasp hard binding with Function.prototype.bind and why subsequent .call() or .apply() cannot override it.

âś“

Recognize lexical this resolution in arrow functions and why they ignore explicit binding methods.

The Interview Problem

What is printed to the console when the following JavaScript code executes, and how do explicit binding and arrow functions alter the value of 'this'?

1const obj = {
2 name: 'Alice',
3 regular() {
4 return this.name;
5 },
6 getArrow() {
7 return () => this.name;
8 },
9};
10
11const bob = { name: 'Bob' };
12const charlie = { name: 'Charlie' };
13
14const extracted = obj.regular;
15const bound = obj.regular.bind(bob);
16const nestedArrow = obj.getArrow();
17
18console.log(
19 obj.regular(),
20 extracted.call(charlie),
21 bound.call(charlie),
22 nestedArrow.call(charlie)
23);
Predict Console Output
Interactive Challenge

Select the option that matches what standard ECMAScript prints to the console:

Alice Charlie Bob Alice

Alice Charlie Charlie Charlie

Alice undefined Bob undefined

Alice Charlie Bob Bob

V8 Engine Execution Trace
Step 1 of 8 (Line 1)

Global Execution Context allocates obj, bob, and charlie in heap memory. obj exposes regular() and getArrow() methods.

Call Stack (Top = Active)
Global Execution Context
Lexical Scope / Bindings
obj:HeapRef#obj ({ name: 'Alice' })
bob:HeapRef#bob ({ name: 'Bob' })
charlie:HeapRef#charlie ({ name: 'Charlie' })
Console Stream
> [empty]

Deep Technical Breakdown

The 4 Rules of 'this' Binding in JavaScript

Unlike lexical scope which is determined at author time, this in standard JavaScript functions is bound dynamically based entirely on the call-site (how the function is invoked):

  1. Default Binding: Standalone function invocation (e.g. fn()). In non-strict mode, this is the global object (window or global). In strict mode ('use strict'), this is undefined.
  2. Implicit Binding: Method invocation preceded by an object reference (e.g. obj.fn()). this is the containing object obj.
  3. Explicit Binding: Invoking via Function.prototype.call(thisArg, ...args) or Function.prototype.apply(thisArg, [args]). Forces this to thisArg.
  4. Hard Binding (.bind): fn.bind(thisArg) returns an ECMAScript Exotic Bound Function Object. Its internal [[BoundThis]] slot permanently stores thisArg. Any subsequent attempts to rebind it via .call(), .apply(), or another .bind() are completely ignored.

The Arrow Function Exception: Lexical this

Arrow functions do NOT have their own this binding ([[ThisMode]]: lexical). They resolve this like any regular variable by walking up the lexical scope chain to the enclosing execution context at the moment of creation. Because they have no internal this slot, call(), apply(), and bind() have no effect on their context.

Common Traps & Mistakes

Believing that chaining `.bind()` works: `fn.bind(a).bind(b)` will ALWAYS bind `this` to `a`, never `b`.

Assuming arrow functions declared inside object literals bind to the object: object literals do NOT create a lexical scope; only functions, blocks, and modules do.

Passing an object method as a callback (e.g., `setTimeout(obj.method, 1000)`), which detaches the method and falls back to default binding.

FAANG Follow-Up Probes
Probe #1

How does the `new` operator interact with a hard-bound function created via `.bind()` (precedence of `new` over `bind`)?

Probe #2

How would you implement a polyfill for `Function.prototype.bind` supporting partial application and `new` instantiation?

Probe #3

What is the difference between `call` and `apply` in V8 performance and argument spreading?