[{"data":1,"prerenderedAt":174},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Ffundamentals\u002Fvariables-scope-hoisting":3},{"page":4,"siblings":166,"blog":171},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"related":157,"seo":158,"seoDescription":159,"stem":160,"subtopic":161,"topic":162,"topicSlug":163,"updated":164,"__hash__":165},"qa\u002Fjavascript\u002Ffundamentals\u002Fvariables-scope-hoisting.md","Variables Scope Hoisting",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"easy","md","JavaScript","javascript",{},true,1,"\u002Fjavascript\u002Ffundamentals\u002Fvariables-scope-hoisting",[23,27,32,36,40,44,48,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153],{"id":24,"difficulty":14,"q":25,"a":26},"var-let-const","What is the difference between var, let and const?","They differ along three axes: **scope**, **hoisting\u002Finitialization**, and\n**reassignment**.\n\n| Keyword | Scope    | Hoisted? | Reassignable? | Redeclarable? |\n| ------- | -------- | -------- | ------------- | ------------- |\n| `var`   | function | yes, init `undefined` | yes | yes |\n| `let`   | block    | yes, in TDZ (uninit)  | yes | no  |\n| `const` | block    | yes, in TDZ (uninit)  | no  | no  |\n\nThe subtle one is `const`: it makes the **binding** constant, **not the\nvalue**. You can't reassign the variable, but if it holds an object or array\nyou can still mutate the contents.\n\n```js\nconst user = { name: 'Ada' }\nuser.name = 'Grace' \u002F\u002F OK — mutating the object the binding points to\nuser = {}           \u002F\u002F TypeError — reassigning the binding\n\nconst list = [1, 2]\nlist.push(3)        \u002F\u002F [1, 2, 3]\n```\n\nModern guidance: default to `const`, use `let` when you genuinely need to\nreassign, and avoid `var`.\n",{"id":28,"difficulty":29,"q":30,"a":31},"hoisting","medium","What is hoisting?","Hoisting is the JavaScript engine processing **declarations** before executing\ncode, so they behave as if \"moved\" to the top of their scope. But *what* gets\nhoisted differs:\n\n- `var` declarations are hoisted **and initialized to `undefined`**, so reading\n  one before its assignment gives `undefined` (no error).\n- **Function declarations** are hoisted **entirely** — you can call them above\n  where they're written.\n- `let`\u002F`const` are hoisted **but left uninitialized** in the *temporal dead\n  zone*; touching them early throws.\n\n```js\nconsole.log(a) \u002F\u002F undefined  (var hoisted, value not yet assigned)\nvar a = 1\n\ngreet()        \u002F\u002F 'hi'  (function declaration fully hoisted)\nfunction greet() { return 'hi' }\n\nconsole.log(b) \u002F\u002F ReferenceError (TDZ)\nlet b = 2\n```\n\nMental model: declarations are \"registered\" first; only the **assignments**\nrun in place.\n",{"id":33,"difficulty":29,"q":34,"a":35},"tdz","What is the temporal dead zone (TDZ)?","The TDZ is the window between **entering a scope** and the line where a\n`let`\u002F`const` variable is actually **declared**. The binding exists (it was\nhoisted) but is *uninitialized*, so any attempt to read or write it in that\nwindow throws a `ReferenceError`.\n\n```js\n{\n  \u002F\u002F TDZ for `x` starts here\n  console.log(x) \u002F\u002F ReferenceError: Cannot access 'x' before initialization\n  let x = 5      \u002F\u002F TDZ ends — x is now initialized\n  console.log(x) \u002F\u002F 5\n}\n```\n\nIt exists on purpose: it turns \"used before declared\" from a silent\n`undefined` bug (the `var` behavior) into a **loud, immediate error**, which\ncatches mistakes earlier and makes `const` semantics sound.\n",{"id":37,"difficulty":14,"q":38,"a":39},"block-scope","What is the difference between block scope and function scope?","**Function scope** (`var`) means a variable is visible **anywhere inside the\nenclosing function**, regardless of which `{ }` blocks it's nested in. **Block\nscope** (`let`\u002F`const`) confines a variable to the **nearest pair of braces** —\nincluding `if`, `for`, `while`, and even a bare `{ }` block.\n\n```js\nfunction demo() {\n  if (true) {\n    var v = 'function-scoped'\n    let l = 'block-scoped'\n  }\n  console.log(v) \u002F\u002F 'function-scoped' — var leaks out of the if\n  console.log(l) \u002F\u002F ReferenceError — l only exists inside the if\n}\n```\n\nBlock scoping is generally safer: variables stay where they're relevant and\nyou avoid accidental leakage across a function — which is one big reason `let`\u002F\n`const` replaced `var`.\n",{"id":41,"difficulty":14,"q":42,"a":43},"redeclare","Can you redeclare variables in the same scope?","`var` lets you **redeclare** the same name in the same scope without\ncomplaint — which silently masks bugs and accidental overwrites. `let` and\n`const` **throw a `SyntaxError`** if you redeclare an identifier in the same\nscope.\n\n```js\nvar x = 1\nvar x = 2      \u002F\u002F allowed (and easy to do by accident)\n\nlet y = 1\nlet y = 2      \u002F\u002F SyntaxError: Identifier 'y' has already been declared\n```\n\nNote this is about *redeclaration in the same scope*. You can still\n**shadow** a `let` in a nested inner block with a new `let` of the same name —\nthat creates a separate binding and is perfectly legal.\n",{"id":45,"difficulty":29,"q":46,"a":47},"global-this","Do var, let and const create properties on the global object?","At the **top level** of a script, a `var` declaration *also* creates a property\non the global object (`window` in browsers, `globalThis` generally). `let` and\n`const` do **not** — they create bindings in a separate *script-scoped* record\nthat the global object can't see.\n\n```js\nvar a = 1\nlet b = 2\nconst c = 3\n\nwindow.a \u002F\u002F 1          \u003C- var leaked onto the global object\nwindow.b \u002F\u002F undefined  \u003C- let did not\nwindow.c \u002F\u002F undefined\n```\n\nThis is another reason to avoid top-level `var`: it pollutes the global\nnamespace and can clash with other scripts or built-ins. (Inside ES modules,\neven top-level `var` doesn't attach to the global object, since module scope\nisn't global scope.)\n",{"id":49,"difficulty":50,"q":51,"a":52},"loop-closure","hard","Why does var behave unexpectedly in a for loop with closures?","Because `var` is **function-scoped**, the loop reuses **one single binding**\nacross all iterations. Any callbacks created in the loop close over that *same*\nvariable, so when they run later they all read its **final value**. `let`\ncreates a **fresh binding each iteration**, so each closure captures its own\ncopy.\n\n```js\nfor (var i = 0; i \u003C 3; i++) setTimeout(() => console.log(i)) \u002F\u002F 3 3 3\nfor (let j = 0; j \u003C 3; j++) setTimeout(() => console.log(j)) \u002F\u002F 0 1 2\n```\n\nWith `var`, by the time the timers fire the loop has long finished and `i` is\n`3`. With `let`, the language re-binds `j` per iteration (and even copies the\nvalue forward for the increment), giving each callback `0`, `1`, `2`. The\npre-`let` fix was an IIFE to manufacture a new scope each pass.\n",{"id":54,"difficulty":14,"q":55,"a":56},"const-array","Can you modify an array declared with const?","Yes. `const` freezes the **binding**, not the **value**. The variable must keep\npointing at the same array, but the array's contents are fully mutable.\n\n```js\nconst arr = [1, 2, 3]\narr.push(4)      \u002F\u002F [1, 2, 3, 4]\narr[0] = 99      \u002F\u002F [99, 2, 3, 4]\narr.length = 0   \u002F\u002F [] — still the same array\narr = []         \u002F\u002F TypeError: Assignment to constant variable\n```\n\nIf you want the *contents* to be immutable too, that's a separate concern —\nuse `Object.freeze(arr)` for a shallow freeze (and note `freeze` is shallow, so\nnested objects can still change).\n",{"id":58,"difficulty":29,"q":59,"a":60},"lexical-scope","What is lexical scope?","Lexical (static) scope means a variable's accessibility is determined by **where\nit's written** in the source code — the nesting of functions\u002Fblocks — not by where\nor how a function is called. The structure is fixed at author time.\n\n```js\nconst outer = 1\nfunction f() {\n  const inner = 2\n  function g() { return outer + inner } \u002F\u002F sees both by lexical nesting\n  return g()\n}\nf() \u002F\u002F 3\n```\n\nBecause scope is determined by position, you can tell what any function can access\njust by reading the code. JavaScript uses lexical scope (unlike languages with\ndynamic scope).\n",{"id":62,"difficulty":29,"q":63,"a":64},"scope-chain","What is the scope chain?","When you reference a variable, the engine looks in the **current scope**, then its\n**enclosing scope**, and so on outward until the global scope — this series of\nlinked scopes is the scope chain. The first match wins; if none is found, it's a\n`ReferenceError`.\n\n```js\nconst a = 'global'\nfunction outer() {\n  const b = 'outer'\n  function inner() {\n    const c = 'inner'\n    return `${a} ${b} ${c}` \u002F\u002F resolves c->inner, b->outer, a->global\n  }\n  return inner()\n}\n```\n\nLookups go **inward-to-outward only** — an outer scope can't see inner variables.\nThis chain is also what closures preserve.\n",{"id":66,"difficulty":29,"q":67,"a":68},"shadowing","What is variable shadowing?","Shadowing is declaring a variable in an inner scope with the **same name** as one\nin an outer scope. The inner variable \"shadows\" the outer one within that scope;\nthe outer remains unchanged outside.\n\n```js\nconst x = 1\nfunction f() {\n  const x = 2   \u002F\u002F shadows the outer x\n  console.log(x) \u002F\u002F 2\n}\nf()\nconsole.log(x)  \u002F\u002F 1 (outer untouched)\n```\n\nShadowing is legal and sometimes useful, but accidental shadowing causes bugs.\nNote you **can't** shadow with `var`\u002F`let` in a way that accesses the outer value\nmid-declaration (TDZ), and linters can warn on shadowing.\n",{"id":70,"difficulty":50,"q":71,"a":72},"fn-decl-vs-block","How are function declarations scoped inside blocks?","In **strict mode** (the default in modules\u002Fclasses), a function declaration inside\na block is **block-scoped** — visible only within that block. In sloppy mode the\nbehavior is inconsistent across engines, which is a common gotcha.\n\n```js\n'use strict'\nif (true) {\n  function foo() { return 1 }\n}\ntypeof foo \u002F\u002F 'undefined' in strict mode — block-scoped\n```\n\nBest practice: don't declare functions inside blocks. Use a **function\nexpression** assigned to a `let`\u002F`const` if you need a conditionally-defined\nfunction, for predictable scoping.\n",{"id":74,"difficulty":50,"q":75,"a":76},"let-switch","Why can let and const be tricky in a switch statement?","A `switch` has **one shared block scope** across all its `case`s. Declaring\n`let`\u002F`const` in one case puts it in the TDZ for the entire switch, so another case\ncan hit a `ReferenceError` or a redeclaration `SyntaxError`.\n\n```js\nswitch (x) {\n  case 1:\n    let y = 'a'   \u002F\u002F y is scoped to the whole switch\n    break\n  case 2:\n    let y = 'b'   \u002F\u002F SyntaxError: 'y' already declared\n    break\n}\n```\n\nFix by wrapping each case body in its own **block** `{ ... }`, giving each `case`\na separate scope.\n",{"id":78,"difficulty":29,"q":79,"a":80},"fn-expr-hoist","Are function expressions hoisted?","The **variable** is hoisted, but the **function value is not** — only the\ndeclaration is. So calling a function expression before its assignment fails\n(`undefined`\u002FTDZ), unlike a function declaration which is fully hoisted.\n\n```js\ndeclared()  \u002F\u002F works — declaration hoisted\nfunction declared() {}\n\nexpressed() \u002F\u002F TypeError: expressed is not a function (var) \u002F ReferenceError (let)\nvar expressed = function () {}\n```\n\nSo function **declarations** are callable above their line; function\n**expressions** (including arrows) follow normal variable hoisting rules and\naren't.\n",{"id":82,"difficulty":50,"q":83,"a":84},"class-hoist","Are class declarations hoisted?","Class declarations **are hoisted** but, like `let`\u002F`const`, remain in the\n**temporal dead zone** — so you **can't use a class before its declaration**.\nUnlike function declarations, they aren't callable early.\n\n```js\nnew Foo()  \u002F\u002F ReferenceError: Cannot access 'Foo' before initialization\nclass Foo {}\n\nbar()      \u002F\u002F function declarations work\nfunction bar() {}\n```\n\nSo \"classes are hoisted\" is technically true, but the TDZ means it behaves like\nnot-hoisted in practice. Always declare classes before using them.\n",{"id":86,"difficulty":50,"q":87,"a":88},"named-fn-expr","What is a named function expression and why use one?","A named function expression gives the function a name that's **only visible inside\nits own body** (not the outer scope). It's useful for self-reference (recursion)\nand clearer stack traces.\n\n```js\nconst factorial = function fact(n) {\n  return n \u003C= 1 ? 1 : n * fact(n - 1) \u002F\u002F `fact` usable inside\n}\nfactorial(5) \u002F\u002F 120\nfact          \u002F\u002F ReferenceError — not visible outside\n```\n\nThe inner name is safer than relying on the outer variable (which could be\nreassigned) and shows up in debuggers instead of \"anonymous.\"\n",{"id":90,"difficulty":14,"q":91,"a":92},"nested-scope-lookup","How does variable lookup work in nested functions?","An inner function can read variables from all of its enclosing scopes, resolved\nvia the scope chain. Each function adds a scope; lookups proceed outward until a\nmatch or the global scope.\n\n```js\nfunction a() {\n  let x = 1\n  function b() {\n    let y = 2\n    function c() { return x + y } \u002F\u002F reaches up two levels\n    return c()\n  }\n  return b()\n}\na() \u002F\u002F 3\n```\n\nInner scopes see outer variables, never the reverse. This nested visibility is the\nfoundation of closures.\n",{"id":94,"difficulty":50,"q":95,"a":96},"implicit-global","What is an accidental (implicit) global variable?","Assigning to a variable **without declaring** it (`x = 5`) in sloppy mode creates\na property on the **global object** instead of erroring — a common source of bugs\nand leaks. **Strict mode** throws a `ReferenceError` instead.\n\n```js\nfunction f() {\n  count = 1   \u002F\u002F no var\u002Flet\u002Fconst -> implicit global\n}\nf()\nconsole.log(count) \u002F\u002F 1 (leaked to global!)\n\n\u002F\u002F strict mode:\n'use strict'\nfunction g() { total = 1 } \u002F\u002F ReferenceError\n```\n\nAlways declare variables, and use strict mode (automatic in modules) so this\nmistake fails loudly.\n",{"id":98,"difficulty":29,"q":99,"a":100},"strict-mode-vars","How does strict mode change variable behavior?","Strict mode tightens several variable rules: assigning to an undeclared variable\n**throws** (no accidental globals), you can't `delete` a variable, duplicate\nparameter names are errors, and `this` is `undefined` instead of the global object\nin plain calls.\n\n```js\n'use strict'\nundeclared = 5   \u002F\u002F ReferenceError\nfunction dup(a, a) {} \u002F\u002F SyntaxError\n```\n\nES modules and class bodies are **always** strict. Strict mode surfaces bugs at\nauthor\u002Fparse time that would otherwise fail silently — a big reason modern code is\nstrict by default.\n",{"id":102,"difficulty":14,"q":103,"a":104},"const-init","Why must a const be initialized at declaration?","Because `const` can be assigned **only once**, you must give it that value at\ndeclaration — there's no later opportunity to assign. Declaring without a value is\na `SyntaxError`.\n\n```js\nconst x = 5   \u002F\u002F\nconst y        \u002F\u002F SyntaxError: Missing initializer in const declaration\n```\n\n`let` and `var` can be declared without a value (defaulting to `undefined`), but\n`const`'s \"assign once\" contract requires the value up front. This also makes\n`const` ineligible for the classic split declare-then-assign pattern.\n",{"id":106,"difficulty":50,"q":107,"a":108},"var-fn-clash","What happens when a var and a function declaration share a name?","During hoisting, **function declarations take precedence** over `var`\ndeclarations with the same name. The `var` declaration is ignored (its\nassignment, if any, still runs in place and can overwrite the function later).\n\n```js\nconsole.log(typeof foo) \u002F\u002F 'function' — function decl wins at hoist time\nvar foo = 'bar'\nfunction foo() {}\nconsole.log(typeof foo) \u002F\u002F 'string' — the assignment ran\n```\n\nSo at the top the name is the function; once execution reaches `foo = 'bar'`, it\nbecomes the string. These clashes are confusing — avoid reusing names.\n",{"id":110,"difficulty":29,"q":111,"a":112},"module-scope","What is module scope?","Each ES module has its own **top-level scope** — variables declared at the top of\na module are **not** global; they're private to that module unless `export`ed.\nEven top-level `var` doesn't attach to the global object.\n\n```js\n\u002F\u002F module.js\nconst secret = 42       \u002F\u002F module-scoped, not global\nexport const api = {}   \u002F\u002F shared only via export\n\u002F\u002F window.secret -> undefined\n```\n\nThis is a major improvement over classic scripts, where top-level `var` polluted\nthe global namespace. Module scope plus strict mode is why modern code avoids many\nlegacy footguns.\n",{"id":114,"difficulty":50,"q":115,"a":116},"let-per-iteration","How does let create a new binding each loop iteration?","In a `for` loop, `let` creates a **fresh binding per iteration** and copies the\nvalue forward — so closures created in the loop each capture their own copy. `var`\nshares one binding across all iterations.\n\n```js\nconst fns = []\nfor (let i = 0; i \u003C 3; i++) fns.push(() => i)\nfns.map(f => f())  \u002F\u002F [0, 1, 2]\n\nconst v = []\nfor (var j = 0; j \u003C 3; j++) v.push(() => j)\nv.map(f => f())    \u002F\u002F [3, 3, 3]\n```\n\nThis per-iteration binding is a deliberate `let` feature that fixes the\nlong-standing closure-in-loop bug.\n",{"id":118,"difficulty":50,"q":119,"a":120},"tdz-typeof","Does typeof protect against the temporal dead zone?","No. `typeof` is safe for **undeclared** identifiers, but a `let`\u002F`const` variable\nin its **TDZ** is declared-but-uninitialized, so even `typeof` throws a\n`ReferenceError`.\n\n```js\ntypeof undeclaredVar  \u002F\u002F 'undefined' (safe)\n\ntypeof x              \u002F\u002F ReferenceError (x is in the TDZ)\nlet x = 1\n```\n\nSo the usual \"use `typeof` to safely check existence\" trick fails for block-scoped\nvariables before their declaration line. The TDZ deliberately makes\nuse-before-declaration an error.\n",{"id":122,"difficulty":29,"q":123,"a":124},"bare-block","What is a bare block and how does it scope variables?","A bare block is a standalone `{ ... }` (not attached to `if`\u002F`for`\u002Fetc.). With\n`let`\u002F`const` it creates a **new block scope**, so variables inside are invisible\noutside — a lightweight way to limit scope. `var` ignores it (function-scoped).\n\n```js\n{\n  let secret = 42\n  var leaked = 1\n}\nconsole.log(leaked) \u002F\u002F 1 (var ignores the block)\nconsole.log(secret) \u002F\u002F ReferenceError (let is block-scoped)\n```\n\nBare blocks can also resolve `switch`\u002Ftemporary-variable naming conflicts by\nisolating declarations.\n",{"id":126,"difficulty":29,"q":127,"a":128},"shadow-nested","Can you shadow a let variable in a nested block?","Yes. A nested block can declare a new `let`\u002F`const` with the same name, creating a\n**separate binding** that shadows the outer one within that block. This is\ndifferent from redeclaration in the **same** scope (which errors).\n\n```js\nlet x = 1\n{\n  let x = 2     \u002F\u002F shadows — different (nested) scope\n  console.log(x) \u002F\u002F 2\n}\nconsole.log(x)  \u002F\u002F 1\n\nlet y = 1\nlet y = 2       \u002F\u002F SyntaxError — same scope\n```\n\nShadowing across scopes is allowed; redeclaring in the same scope is not.\n",{"id":130,"difficulty":50,"q":131,"a":132},"dynamic-vs-lexical","What is the difference between lexical and dynamic scoping?","- **Lexical scoping** (what JS uses): a function's free variables resolve based on\n  **where it's defined** in the source.\n- **Dynamic scoping** (some other languages): free variables resolve based on the\n  **call stack at runtime** — who called the function.\n\n```js\nlet x = 'global'\nfunction inner() { return x }\nfunction outer() { let x = 'outer'; return inner() }\nouter() \u002F\u002F 'global' — lexical: inner sees where it was DEFINED\n\u002F\u002F (a dynamically-scoped language would return 'outer')\n```\n\nJS's only \"dynamic\" feature is `this`, which is bound by the call site — but\nordinary variable lookup is always lexical.\n",{"id":134,"difficulty":29,"q":135,"a":136},"hoisting-mechanism","What actually happens during hoisting (the two phases)?","JavaScript runs in two phases per scope: a **creation (compilation) phase** that\nregisters all declarations (allocating `var` as `undefined`, `let`\u002F`const` as\nuninitialized in the TDZ, functions fully), and an **execution phase** that runs\nthe code and performs assignments in order.\n\n```js\n\u002F\u002F creation phase registers: a (undefined), greet (function)\nconsole.log(a)  \u002F\u002F undefined\nvar a = 1       \u002F\u002F execution: a becomes 1\ngreet()         \u002F\u002F already callable\nfunction greet() {}\n```\n\nSo \"hoisting\" isn't physical code movement — it's declarations being processed\nbefore any line executes. Only assignments happen in place.\n",{"id":138,"difficulty":29,"q":139,"a":140},"var-leak","Why is var leaking out of blocks a problem?","`var` is function-scoped, so a `var` declared inside an `if`\u002F`for`\u002Fblock is visible\nthroughout the **entire enclosing function** — leaking beyond where it's relevant,\nwhich causes accidental reuse and bugs.\n\n```js\nfunction f() {\n  for (var i = 0; i \u003C 3; i++) {}\n  console.log(i) \u002F\u002F 3 — i leaked out of the loop\n\n  if (true) { var temp = 'x' }\n  console.log(temp) \u002F\u002F 'x' — leaked out of the if\n}\n```\n\n`let`\u002F`const` confine variables to their block, keeping scope tight. This leakage\nis a primary reason to avoid `var`.\n",{"id":142,"difficulty":50,"q":143,"a":144},"deep-freeze","How do you make an object deeply immutable?","`Object.freeze` is **shallow** — it freezes the top-level properties but nested\nobjects remain mutable. For deep immutability you must recursively freeze.\n\n```js\nconst obj = Object.freeze({ a: 1, nested: { b: 2 } })\nobj.a = 9          \u002F\u002F ignored (or throws in strict mode)\nobj.nested.b = 99  \u002F\u002F still mutable! freeze is shallow\n\nfunction deepFreeze(o) {\n  Object.values(o).forEach(v => v && typeof v === 'object' && deepFreeze(v))\n  return Object.freeze(o)\n}\n```\n\nCheck frozen status with `Object.isFrozen`. For shared constants, deep-freezing\nprevents accidental mutation.\n",{"id":146,"difficulty":29,"q":147,"a":148},"iife-scope-isolation","How does an IIFE isolate scope?","An IIFE runs immediately and creates a **private function scope**, so variables\ninside never touch the enclosing\u002Fglobal scope. Before block scoping and modules, it\nwas the main tool to avoid polluting globals and to create private state.\n\n```js\n(function () {\n  var temp = 'private'   \u002F\u002F not global\n  \u002F\u002F setup work...\n})()\ntypeof temp \u002F\u002F 'undefined' — isolated\n```\n\nToday, block scope (`{ let ... }`) and ES modules cover most of these needs, but\nIIFEs still appear in bundled code and for one-off encapsulation.\n",{"id":150,"difficulty":14,"q":151,"a":152},"let-vs-const-when","When should you use let vs const?","Default to **`const`** — it signals the binding won't be reassigned, preventing\naccidental reassignment and making code easier to reason about. Use **`let`** only\nwhen you genuinely need to reassign (counters, accumulators, reassigned in\nbranches). Avoid `var`.\n\n```js\nconst MAX = 100          \u002F\u002F never reassigned\nconst user = { id: 1 }   \u002F\u002F const, but you can still mutate the object\nlet total = 0            \u002F\u002F reassigned in a loop\nfor (const item of items) total += item.price\n```\n\n\"const by default, let when needed\" is the widely-adopted convention. Remember\n`const` blocks reassignment, not mutation.\n",{"id":154,"difficulty":29,"q":155,"a":156},"global-pollution","Why are global variables discouraged?","Globals are accessible and mutable from **anywhere**, so they create hidden\ncoupling, name collisions between scripts\u002Flibraries, hard-to-trace bugs, and\nproblems in concurrent\u002Ftesting contexts. Any code can change them unexpectedly.\n\n```js\n\u002F\u002F global state anyone can clobber\nvar config = {}\n\u002F\u002F encapsulate in a module or closure\nexport const config = createConfig()\n```\n\nMinimize globals by using **modules** (module scope), closures, and passing\ndependencies explicitly. When a true global is needed, namespace it under a single\nobject to limit collisions.\n",null,{"description":11},"Common JavaScript interview questions on var, let and const, scope, hoisting and the temporal dead zone, with clear answers and examples.","javascript\u002Ffundamentals\u002Fvariables-scope-hoisting","Variables, Scope & Hoisting","Fundamentals","fundamentals","2026-06-17","1OhvPeamj0K5ICmSSBRUFJ9iY7c4aoSeIv0ARSpSdac",[167,168],{"subtopic":161,"path":21,"order":20},{"subtopic":169,"path":170,"order":12},"Data Types & Coercion","\u002Fjavascript\u002Ffundamentals\u002Fdata-types-coercion",{"path":172,"title":173},"\u002Fblog\u002Fjavascript-variables-scope-hoisting","JavaScript Variables, Scope & Hoisting — var, let & const Explained",1781808676465]