Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Scope and Hoisting in JavaScript

Scope and Hoisting in JavaScript

~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

"Scope" determines WHERE in the code a variable is visible. This chapter clarifies the crucial difference between var and let/const, which we've deliberately avoided since chapter 4.

Block scope (let/const) vs. function scope (var)

if (true) {
  let blockScoped = 'only visible here';
  var functionScoped = 'escapes the block';
}

console.log(functionScoped); // 'escapes the block' - var 'escapes' the if block!
console.log(blockScoped);    // ReferenceError: blockScoped is not defined

let and const are bound to the immediately surrounding block ({ } – whether an if, a for, or a plain block). var IGNORES blocks entirely and is only bound to the surrounding FUNCTION (or the global scope) – this is the main source of confusion and the reason var is considered outdated.

The classic var loop trap

// With var: all three timeouts print '3' - NOT what you'd want!
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log('var:', i), 0);
}
// Output: var: 3, var: 3, var: 3

// With let: each iteration gets its OWN binding
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log('let:', j), 0);
}
// Output: let: 0, let: 1, let: 2

The reason: there's only ONE single, shared i for the entire var loop – by the time the timeouts (chapters 23/24) finally run, the loop has long finished and i sits at 3. With let, EVERY iteration creates a NEW binding of j, correctly captured by the closure (chapter 16) of each callback function.

Hoisting in detail

"Hoisting" describes how declarations (not assignments!) are already known BEFORE their actual line while the file is being read. The three declaration kinds behave differently:

console.log(withVar); // undefined - hoisted, but with no value yet
console.log(withLet); // ReferenceError: Cannot access 'withLet' before initialization

var withVar = 'value';
let withLet = 'value';

var declarations are hoisted AND pre-initialized with undefined. let/const are also hoisted, but stay in the so-called "temporal dead zone" until their actual line – accessing them before that throws an error instead of silently returning undefined. This is SAFER in practice: a typo or a wrong code ordering surfaces immediately as an error instead of hiding as a silent undefined.

Tipp: Function declarations (chapter 8) get FULLY hoisted (including the function body) – that's why the call before the definition worked in chapter 8. Function expressions with const/let, on the other hand, have the same temporal-dead-zone behavior as any other let/const variable.

Avoiding global scope

A variable declared with var OUTSIDE any function ends up in the global scope and is thus visible AND mutable from EVERYWHERE in the program – a common source of bugs in larger programs, since any file could accidentally reuse the same global name. ES modules (chapter 21) automatically encapsulate each file in its own scope, which greatly reduces this risk in modern code.