ReviseAlgo Logo

JavaScript Interview Prep

this Keyword Edge Cases

Master the tricky rules, implicit and explicit binding traps, arrow function lexical binding, method detachment, and edge cases surrounding the `this` keyword in JavaScript.

this Keyword Edge Cases & Interview Traps

In JavaScript, the this keyword refers to the execution context of a function call. Unlike lexically scoped variables, standard functions determine this at runtime depending on how the function is invoked, not where it was declared.

1. The 4 Golden Rules of this Binding

JavaScript evaluates this based on four invocation rules (ordered from lowest to highest priority):

1. Default Binding: Called standalone (foo()) \rightarrow global object (window or globalThis), or undefined in strict mode ('use strict'). 2. Implicit Binding: Called via object property (obj.foo()) \rightarrow obj. 3. Explicit Binding: Called via .call(), .apply(), or .bind() \rightarrow explicitly passed object. 4. new Binding: Called via constructor (new Foo()) \rightarrow newly created object.

2. Deep Dive into Edge Cases

Edge Case 1: Method Detachment (Losing Implicit Binding)

When an object method is extracted into a variable or passed as a callback, it loses its implicit binding.

#### Solution: Explicitly bind or wrap in an arrow function

Edge Case 2: Arrow Functions Do NOT Have Their Own this

Arrow functions inherit this from their enclosing lexical scope at the time of creation. .call(), .apply(), and .bind() are silently ignored on arrow functions.

Edge Case 3: Chaining .bind() Does Not Change Target

Calling .bind() multiple times on a function returns a new function bound to the first context provided.

Edge Case 4: new Binding Overrides Explicit Binding

The new operator overrides functions bound with .bind().

Edge Case 5: Passing null or undefined to .call() / .apply()

In non-strict mode, passing null or undefined falls back to globalThis (window). In strict mode, this remains null or undefined.

3. Interactive Code Playground

Run and modify the code below to see how binding rules interact at runtime:

4. Edge Case Matrix

Invocation StyleStrict Mode thisNon-Strict Mode thisCan be overridden by new?
fn()undefinedglobalThis (window)Yes
obj.fn()objobjYes
fn.call(ctx)ctxctx (or window if null/undefined)Yes
fn.bind(ctx)ctx (permanently)ctx (permanently)Yes (new wins over bind)
Arrow () => {}Enclosing Lexical thisEnclosing Lexical thisCannot be called with new

5. Frequently Asked Interview Questions

Q1: What is the output of the following snippet?

Answer: 1. fn() logs 0 or 10 (or undefined in strict mode / let variable global scope). 2. arguments[0]() invokes fn as a method of the arguments array object (arguments.0()). Therefore, this is arguments, and arguments.length is 2 (since 2 arguments fn, 1 were passed). Output: 2.

Q2: How does this behave inside class constructors vs class methods?

Answer: Inside ES6 class method declarations, methods automatically run in strict mode. Passing a class method as an un-bound callback results in this being undefined (throwing a TypeError: Cannot read properties of undefined).

6. Summary Checklist

  • [x] Standard functions determine this at call-site; arrow functions at declaration-site.
  • [x] Detached methods lose implicit binding and default to global/undefined context.
  • [x] Chained .bind() calls can never change the context established by the first .bind().
  • [x] The new keyword overrides explicit .bind() calls.
  • [x] Array methods like .map(fn, thisArg) and .forEach(fn, thisArg) accept a optional thisArg parameter.