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 Style | Strict Mode this | Non-Strict Mode this | Can be overridden by new? |
|---|---|---|---|
fn() | undefined | globalThis (window) | Yes |
obj.fn() | obj | obj | Yes |
fn.call(ctx) | ctx | ctx (or window if null/undefined) | Yes |
fn.bind(ctx) | ctx (permanently) | ctx (permanently) | Yes (new wins over bind) |
Arrow () => {} | Enclosing Lexical this | Enclosing Lexical this | Cannot be called with new |
5. Frequently Asked Interview Questions
Q1: What is the output of the following snippet?
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
this at call-site; arrow functions at declaration-site..bind() calls can never change the context established by the first .bind().new keyword overrides explicit .bind() calls..map(fn, thisArg) and .forEach(fn, thisArg) accept a optional thisArg parameter.