Study notes · 11% of the exam

Scope, Closures and this

Know exactly where a name is resolved and what `this` is for any call: scopes, hoisting and the TDZ, closures over variables, the four `this` rules plus arrows, and the quirks of `arguments`, `bind` and default parameters.

Key points

  1. 1

    All declarations are hoisted: var as undefined, functions with their body, and let/const/class uninitialised (the temporal dead zone) until their line runs. Even typeof throws in the TDZ.

  2. 2

    Closures capture variables, not values. for (let i ...) makes a fresh binding per iteration; a let declared outside the loop, or a var, is shared by every closure.

  3. 3

    this is set by the call: new beats explicit (call/apply/bind), which beats a method call, which beats a plain call (undefined in strict mode, globalThis in sloppy mode).

  4. 4

    Arrow functions have no own this, arguments, super or new.target. They resolve them lexically, which is why they make good callbacks but poor object methods.

  5. 5

    bind fixes this and leading arguments, returns a new function every time (so keep the reference for removeEventListener), and is ignored under new except for its arguments.

  6. 6

    Default parameters run left to right in their own scope. With defaults, the body's vars live in a separate scope, and fn.length stops counting at the first default.

  7. 7

    Only sloppy functions with simple parameter lists get a mapped arguments object. Prefer rest parameters.

Common traps

  • (0, obj.method)() and (obj.m = obj.m)() lose this, while (obj.method)() keeps it.

  • In sloppy scripts, a function declared inside a block also leaks to the enclosing scope (Annex B), first as undefined.

  • V8 (Chrome, Node.js) does not implement proper tail calls, so deep recursion still overflows the stack.

Test yourself on Scope, Closures and this

Ten questions, with the answer and explanation after each one.