var, let & const in Js | what is Temporal Dead Zone?
var & let
var & let both used for variable declaration in JavaScript but the different between them is var is global scope and let is block scope.
var a = 10;var a = 100;console.log(a);
100It will print 100 but why?
but in this case let is act like strict teacher😂 because he not allows two same name student / variables. it throw syntaxError identifier 'a' has already been declared.let a = 10;let a = 100;console.log(a)
when code is run execution context created. memory allocation phase starts, a put the value undefined and same like a let x store value undefined but in different place of memory.var a = 10;let x = 100;console.log(x);
so in this case x is assign but in different memory location so js engine won’t found the x in global execution context, so it throw reference Error cannot access 'x' before initialization. this means you can not access variable before declaration.console.log(x);let x = 100;
execution context created and memory allocation phase starts, during this both variable are store in different memory phase and assigned undefined means it happens in temporal dead zone. then assigned a : 10 and b : 100 .let a = 10;const b = 100;
you can not do the same thing in const it throw syntaxError: missing intializer in const declaration it means the value declare using const it can not change.const b;b = 100;console.log(b)
Episode - var vs let vs const in JavaScript — The Complete Guide
Hey everyone! Welcome back to Namaste JavaScript. Today we are going to master one of the most important and frequently asked topics in JavaScript — var, let, and const!
These three keywords are how we declare variables in JavaScript. They look similar but they behave very differently under the hood. By the end of this episode, you will know exactly when to use which one — and why!
What we will cover:
- Brief History — Why let and const were introduced
- Scope — Global, Function, Block
- var — Deep Dive
- let — Deep Dive
- const — Deep Dive
- Hoisting Differences
- Re-declaration and Re-assignment
- Temporal Dead Zone (TDZ)
- var in Loops vs let in Loops
- const with Objects and Arrays
- Common Mistakes and Gotchas
- When to Use Which
- Famous Interview Questions
Brief History — Why let and const Were Introduced
JavaScript was created in 1995. For the first 20 years, var was the only way to declare variables.
The Problem with var:
======================
// var had some quirky behaviors that caused real bugs:
// 1. No block scope — leaks out of if/for/while blocks
for (var i = 0; i < 3; i++) { }
console.log(i); // 3 — leaked out of the loop!
// 2. Can be re-declared (silent bug!)
var name = "Shreyesh";
var name = "John"; // No error! Overwrote silently!
console.log(name); // "John"
// 3. Hoisted as undefined — confusing behavior
console.log(x); // undefined (instead of an error!)
var x = 5;
// These behaviors caused hard-to-find bugs in large codebases.
// ES6 (2015) introduced 'let' and 'const' to fix these!
JavaScript Variable Declaration Timeline: ========================================== 1995: JavaScript created → only 'var' exists 2015: ES6 (ES2015) introduced → 'let' and 'const' added Today: 'var' is still valid but mostly avoided in modern code. The recommendation today: ✅ Use 'const' by default ✅ Use 'let' when you need to reassign ❌ Avoid 'var' in modern code
Understanding Scope First
Before diving into each keyword, you need to understand the three types of scope in JavaScript.
1. Global Scope
================
Variables declared outside any function or block.
Accessible everywhere in your program.
var globalVar = "I am global";
let globalLet = "I am also global";
function test() {
console.log(globalVar); // ✅ Accessible
console.log(globalLet); // ✅ Accessible
}
test();
console.log(globalVar); // ✅ Accessible
2. Function Scope (Local Scope)
================================
Variables declared inside a function.
Accessible ONLY within that function.
function myFunc() {
var funcVar = "function scoped";
let funcLet = "also function scoped";
console.log(funcVar); // ✅
console.log(funcLet); // ✅
}
myFunc();
console.log(funcVar); // ❌ ReferenceError
console.log(funcLet); // ❌ ReferenceError
// Both var and let/const are function-scoped when inside a function.
// The KEY difference is with BLOCK scope!
3. Block Scope
===============
A block is anything inside { curly braces }.
if blocks, for loops, while loops, standalone blocks, etc.
{
var blockVar = "var ignores blocks!";
let blockLet = "let respects blocks!";
const blockConst = "const respects blocks!";
}
console.log(blockVar); // ✅ "var ignores blocks!" — leaked out!
console.log(blockLet); // ❌ ReferenceError
console.log(blockConst); // ❌ ReferenceError
// THIS is the biggest difference:
// var → function scoped (block scope doesn't exist for var)
// let/const → block scoped (stays inside {})
Scope Hierarchy: ================= ┌─────────────────────────────────────────────┐ │ Global Scope │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ Function Scope │ │ │ │ │ │ │ │ ┌───────────────────────────────┐ │ │ │ │ │ Block Scope (if/for/while) │ │ │ │ │ │ │ │ │ │ │ │ var → escapes to Function │ │ │ │ │ │ let → stays in Block ✅ │ │ │ │ │ │ const→ stays in Block ✅ │ │ │ │ │ └───────────────────────────────┘ │ │ │ └──────────────────────────────────────┘ │ └─────────────────────────────────────────────┘
var — Deep Dive
Let us understand everything about var — its behaviors, quirks, and why modern JavaScript avoids it.
var — Scope
var is FUNCTION-SCOPED:
========================
function test() {
if (true) {
var x = 10; // declared inside if-block
console.log(x); // 10 ✅
}
console.log(x); // 10 ✅ — leaked out of if block!
}
test();
console.log(x); // ❌ ReferenceError — stopped by function
// var respects function boundaries, NOT block boundaries.
var Leaking From Loops:
========================
for (var i = 0; i < 3; i++) {
console.log(i); // 0, 1, 2
}
console.log(i); // 3 — leaked out of for loop!
while (var j = 0; j < 3; j++) { } // SyntaxError (can't do this)
// But:
var j = 0;
while (j < 3) {
j++;
}
console.log(j); // 3 — accessible after while loop
var — Re-declaration
// ✅ var can be re-declared (no error): var name = "Shreyesh"; var name = "John"; // No error! Silently overwrites! var name = "JavaScript"; // No error again! console.log(name); // "JavaScript" // This is a source of BUGS! // In a large file, you might accidentally redeclare a variable // and overwrite data — JavaScript won't even warn you!
var — Re-assignment
// ✅ var can be re-assigned: var score = 10; score = 20; score = 30; console.log(score); // 30 // Re-assignment is fine for all three (var, let, const) // except const — which cannot be re-assigned.
var — Hoisting
// var is hoisted and initialized to undefined: console.log(a); // undefined (no error!) var a = 5; console.log(a); // 5 // JavaScript sees this as: var a; // hoisted to top console.log(a); // undefined a = 5; // assignment stays in place console.log(a); // 5
var — Global Object Property
// ⚠️ var declared at global scope becomes a property of window (browser): var globalVar = "I am global"; console.log(window.globalVar); // "I am global" — on window object! let globalLet = "I am global too"; console.log(window.globalLet); // undefined — NOT on window object! // var pollutes the global window object. // This can cause conflicts with third-party libraries!
Summary of var: ================ ✅ Function scoped ✅ Can be re-declared ✅ Can be re-assigned ✅ Hoisted (initialized to undefined) ⚠️ Leaks out of blocks (if, for, while) ⚠️ Adds to global window object ⚠️ Can be re-declared silently (bug risk) ⚠️ Hoisted as undefined (can confuse debugging)
let — Deep Dive
let was introduced in ES6 to solve the problems with var. It gives us proper block scoping and prevents accidental re-declaration.
let — Scope
// let is BLOCK-SCOPED:
{
let x = 10;
console.log(x); // 10 ✅
}
console.log(x); // ❌ ReferenceError: x is not defined
if (true) {
let y = 20;
console.log(y); // 20 ✅
}
console.log(y); // ❌ ReferenceError
for (let i = 0; i < 3; i++) {
console.log(i); // 0, 1, 2 ✅
}
console.log(i); // ❌ ReferenceError — stays inside loop!
let in Nested Blocks:
======================
let outer = "outer";
{
let inner = "inner";
console.log(outer); // ✅ "outer" (inner block can access outer)
console.log(inner); // ✅ "inner"
}
console.log(outer); // ✅ "outer"
console.log(inner); // ❌ ReferenceError
// Inner block can access outer scope, but not vice versa.
// This is the scope chain — works the same as closures!
let — Re-declaration
// ❌ let CANNOT be re-declared in the same scope:
let name = "Shreyesh";
let name = "John"; // SyntaxError: Identifier 'name' has already been declared
// ✅ But can be declared in a different scope (different block):
let name = "Shreyesh";
{
let name = "John"; // ✅ Different scope — fine!
console.log(name); // "John"
}
console.log(name); // "Shreyesh" (outer name unchanged)
let — Re-assignment
// ✅ let CAN be re-assigned: let score = 10; score = 20; // ✅ Fine! score = 30; // ✅ Fine! console.log(score); // 30 // This is the whole point of let over const — // use let when you NEED to change the value!
let — Hoisting and TDZ
// let IS hoisted, but placed in Temporal Dead Zone (TDZ): console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization let b = 5; // The TDZ is the gap between hoisting and initialization: // ───────────────────────────────────────────────── // Start of scope ← b hoisted HERE (TDZ begins) // ... // console.log(b); ← INSIDE TDZ → ReferenceError! // ... // let b = 5; ← TDZ ENDS HERE, b = 5 // ... // console.log(b); ← SAFE → 5 // ─────────────────────────────────────────────────
// let is NOT added to the global window object: let globalLet = "hello"; console.log(window.globalLet); // undefined (not polluting window!)
Summary of let: ================ ✅ Block scoped ✅ Can be re-assigned ✅ Hoisted (but in TDZ — not accessible before declaration) ✅ NOT added to global window object ❌ Cannot be re-declared in the same scope ⚠️ Accessing before declaration → ReferenceError (TDZ)
const — Deep Dive
const stands for "constant". It is like let but with one extra rule — it cannot be re-assigned after the initial assignment.
const — Declaration and Initialization
// ✅ const must be initialized at declaration: const PI = 3.14159; // ✅ Correct // ❌ Cannot declare without initializing: const MAX; // SyntaxError: Missing initializer in const declaration MAX = 100; // This won't even get here // const MUST be given a value when declared!
const — Re-assignment
// ❌ const CANNOT be re-assigned: const PI = 3.14; PI = 3.14159; // ❌ TypeError: Assignment to constant variable. const name = "Shreyesh"; name = "John"; // ❌ TypeError: Assignment to constant variable. // Once assigned, the binding is PERMANENT. // The variable always points to the same value/reference.
const — Scope
// const is BLOCK-SCOPED (same as let):
{
const x = 10;
console.log(x); // 10 ✅
}
console.log(x); // ❌ ReferenceError
if (true) {
const msg = "Hello!";
console.log(msg); // ✅ "Hello!"
}
console.log(msg); // ❌ ReferenceError
const — Re-declaration
// ❌ const CANNOT be re-declared in the same scope:
const name = "Shreyesh";
const name = "John"; // SyntaxError
// ✅ Can be declared in a different block scope:
const name = "Shreyesh";
{
const name = "John"; // ✅ Different block
console.log(name); // "John"
}
console.log(name); // "Shreyesh"
const — Hoisting and TDZ
// const behaves exactly like let with TDZ: console.log(SIZE); // ❌ ReferenceError: Cannot access 'SIZE' before initialization const SIZE = 100; console.log(SIZE); // 100 ✅ // Same TDZ rules as let apply to const.
const with Objects — VERY IMPORTANT!
// ⚠️ const does NOT make objects/arrays immutable!
// It only prevents RE-ASSIGNMENT of the variable!
const person = { name: "Shreyesh", age: 25 };
// ❌ Cannot re-assign the variable:
person = { name: "John" }; // TypeError: Assignment to constant variable
// ✅ But CAN modify the object's properties:
person.name = "John"; // ✅ Works!
person.age = 30; // ✅ Works!
person.city = "Mumbai"; // ✅ Works — can even add new properties!
console.log(person); // { name: "John", age: 30, city: "Mumbai" }
// const only locks the REFERENCE (the binding),
// NOT the content of what it points to!
const with Arrays:
===================
const fruits = ["apple", "banana"];
// ❌ Cannot re-assign:
fruits = ["mango"]; // TypeError
// ✅ Can mutate the array:
fruits.push("mango"); // ✅ Works!
fruits[0] = "grapes"; // ✅ Works!
fruits.length = 0; // ✅ Clears array — works!
console.log(fruits); // ["grapes", "banana", "mango"]
How to make objects truly immutable:
======================================
const person = Object.freeze({
name: "Shreyesh",
age: 25
});
person.name = "John"; // ❌ Silently fails in non-strict mode
// ❌ TypeError in strict mode
console.log(person.name); // "Shreyesh" — unchanged!
// Object.freeze() makes the top-level properties immutable.
// BUT it's SHALLOW — nested objects are still mutable!
const config = Object.freeze({
db: { host: "localhost" } // nested object NOT frozen!
});
config.db.host = "production"; // ✅ This still works!
console.log(config.db.host); // "production"
// For deep immutability, use a deep freeze utility or libraries like Immer.
Summary of const: ================== ✅ Block scoped ✅ Hoisted (but in TDZ — not accessible before declaration) ✅ NOT added to global window object ✅ Must be initialized at declaration ❌ Cannot be re-assigned ❌ Cannot be re-declared in the same scope ⚠️ Does NOT make objects/arrays immutable — only the binding is constant ⚠️ Accessing before declaration → ReferenceError (TDZ)
Hoisting — Side by Side Comparison
// var — hoisted as undefined: console.log(a); // undefined (no error) var a = 1; // let — hoisted but TDZ: console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 2; // const — hoisted but TDZ: console.log(c); // ReferenceError: Cannot access 'c' before initialization const c = 3;
Why does TDZ exist for let and const? ======================================= JavaScript creators wanted to DISCOURAGE the bad habit of using variables before declaring them. With var: console.log(x); // undefined — confusing, but no error var x = 5; They designed let and const to SCREAM at you: console.log(x); // ReferenceError — "declare before use!" let x = 5; The TDZ is a SAFETY FEATURE that enforces good coding practices!
Checking TDZ in DevTools:
==========================
function example() {
debugger; // Pause here in browser DevTools
let myVar = 5; // myVar is in TDZ above this line
}
// In DevTools → Scope panel:
// You'll see myVar listed under "Block" but with value: uninitialized
// This confirms let IS hoisted, but in TDZ!
Re-declaration and Re-assignment Summary
Re-declaration (same scope): ============================= var x = 1; var x = 2; // ✅ No error (bad but allowed) let y = 1; let y = 2; // ❌ SyntaxError const z = 1; const z = 2; // ❌ SyntaxError Re-assignment: =============== var a = 1; a = 2; // ✅ let b = 1; b = 2; // ✅ const c = 1; c = 2; // ❌ TypeError ┌──────────────┬─────────────────┬────────────────┐ │ │ Re-declaration │ Re-assignment │ ├──────────────┼─────────────────┼────────────────┤ │ var │ ✅ │ ✅ │ │ let │ ❌ │ ✅ │ │ const │ ❌ │ ❌ │ └──────────────┴─────────────────┴────────────────┘
var vs let in Loops — Critical Difference
This is one of the most important practical differences between var and let!
// ❌ var in loop — all callbacks share ONE 'i':
const funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(function() {
return i;
});
}
console.log(funcs[0]()); // 3 (expected 0!)
console.log(funcs[1]()); // 3 (expected 1!)
console.log(funcs[2]()); // 3 (expected 2!)
// WHY?
// var i is FUNCTION-SCOPED → only ONE 'i' for all iterations
// When the loop ends, i = 3
// All three functions close over the SAME 'i' → all print 3
// ✅ let in loop — each iteration gets its OWN 'i':
const funcs = [];
for (let i = 0; i < 3; i++) {
funcs.push(function() {
return i;
});
}
console.log(funcs[0]()); // 0 ✅
console.log(funcs[1]()); // 1 ✅
console.log(funcs[2]()); // 2 ✅
// WHY?
// let i is BLOCK-SCOPED → a NEW 'i' is created for EACH iteration!
// Each function closes over its own separate 'i'
Under the hood — what let does in a for loop:
==============================================
for (let i = 0; i < 3; i++) {
// JavaScript creates a NEW binding of 'i' for each iteration
// Roughly equivalent to:
}
// Iteration 0: { let i = 0; /* body */ }
// Iteration 1: { let i = 1; /* body */ }
// Iteration 2: { let i = 2; /* body */ }
// Each block has its OWN 'i'!
// This is why closures inside let-loops work correctly.
setTimeout + Loop — Famous Interview Example:
=============================================
// ❌ With var:
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), i * 1000);
}
// After 1s: 4
// After 2s: 4
// After 3s: 4
// ✅ With let:
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), i * 1000);
}
// After 1s: 1
// After 2s: 2
// After 3s: 3
// let creates a new 'i' per iteration → each setTimeout
// captures its own separate value!
Common Mistakes and Gotchas
Gotcha 1: const Does Not Mean Immutable
// ❌ Misconception: "const makes things immutable"
const user = { name: "Shreyesh" };
user.name = "John"; // ✅ This WORKS — const doesn't prevent this!
// ✅ Reality: const prevents RE-ASSIGNMENT of the variable
user = { name: "John" }; // ❌ THIS is what const prevents
// Remember:
// const → "this variable will always point to the same thing"
// NOT → "this thing will never change"
Gotcha 2: var Inside if Blocks
// ❌ Surprising:
var x = 1;
if (true) {
var x = 2; // This RE-DECLARES the SAME 'x'!
console.log(x); // 2
}
console.log(x); // 2 — outer x was overwritten!
// ✅ With let:
let y = 1;
if (true) {
let y = 2; // Different 'y' — in block scope!
console.log(y); // 2
}
console.log(y); // 1 — outer y is SAFE!
Gotcha 3: Shadowing
// Variable shadowing — inner variable "shadows" outer one:
let name = "Global";
function test() {
let name = "Function"; // Shadows global 'name'
console.log(name); // "Function"
{
let name = "Block"; // Shadows function 'name'
console.log(name); // "Block"
}
console.log(name); // "Function" (block shadow is gone)
}
test();
console.log(name); // "Global" (function shadow is gone)
// Shadowing with var:
var city = "Mumbai";
function test2() {
var city = "Delhi"; // Shadows global city — OK
console.log(city); // "Delhi"
}
test2();
console.log(city); // "Mumbai" ✅ (function scope protected global)
// BUT — var in a block does NOT shadow, it OVERWRITES:
var country = "India";
{
var country = "USA"; // Same variable! Overwrites!
}
console.log(country); // "USA" — original value lost!
Gotcha 4: Forgetting to Initialize const
// ❌ Common mistake with const: const MAX_SIZE; // SyntaxError: Missing initializer in const declaration // ✅ Always initialize const immediately: const MAX_SIZE = 100; // If you're unsure of the value at declaration time → use let instead!
Gotcha 5: typeof in TDZ
// typeof is normally "safe" for undeclared variables: console.log(typeof undeclaredVar); // "undefined" (no error!) // But typeof does NOT protect from TDZ: console.log(typeof myLet); // ❌ ReferenceError (TDZ!) let myLet = 5; // typeof is only safe for variables that are TRULY undeclared. // It cannot save you from TDZ!
Gotcha 6: const in Loops
// ❌ const in a for loop (increment fails):
for (const i = 0; i < 3; i++) { // TypeError on i++ (re-assignment!)
console.log(i);
}
// ✅ const works in for...of and for...in (new binding each time):
const arr = [10, 20, 30];
for (const val of arr) {
console.log(val); // 10, 20, 30 — each iteration is a new binding!
}
for (const key in { a: 1, b: 2 }) {
console.log(key); // "a", "b"
}
// for...of and for...in create a new const binding each iteration
// — that's why const works there but not in a regular for loop.
When to Use Which — Best Practices
The Modern JavaScript Rule:
============================
1. DEFAULT to const
Use it for everything unless you know you need to reassign.
2. Use let when you NEED to reassign
Counters, accumulators, loop variables, state that changes.
3. Avoid var
There is no modern use case where var is better than let/const.
Examples:
==========
// ✅ Use const for:
const PI = 3.14159;
const MAX_USERS = 100;
const API_URL = "https://api.example.com";
const user = { name: "Shreyesh" }; // object contents can still change
const arr = [1, 2, 3]; // array contents can still change
// ✅ Use let for:
let count = 0;
count++; // reassignment
let total = 0;
for (let i = 0; i < 10; i++) {
total += i; // both let variables need reassignment
}
let message;
if (condition) {
message = "Success";
} else {
message = "Error";
}
// ❌ Avoid var:
var x = 1; // Replace with const or let
Thinking Model: ================ Ask yourself: "Will this variable's value ever change?" YES → use let NO → use const Still not sure? → use const first. If you get a TypeError for reassignment, change it to let.
Interview Questions
Q1: What is the difference between var, let, and const?
"var is function-scoped, can be re-declared and re-assigned, and is hoisted as undefined. let is block-scoped, cannot be re-declared in the same scope, can be re-assigned, and is hoisted into the TDZ. const is block-scoped, cannot be re-declared or re-assigned, must be initialized at declaration, and is also hoisted into the TDZ. In modern JavaScript, prefer const by default and let when reassignment is needed — avoid var."
Q2: What is the Temporal Dead Zone?
"The TDZ is the period between when a let or const variable is hoisted and when it is initialized. During this period, accessing the variable throws a ReferenceError. It exists from the start of the block scope until the line where the variable is declared. The TDZ is a safety feature that enforces declaring variables before using them."
Q3: Does const make objects immutable?
"No. const only prevents re-assignment of the variable binding — the variable will always point to the same object or array, but the contents of that object or array can still be modified. To truly make an object immutable, use Object.freeze(), but note that this is shallow — nested objects are still mutable."
Q4: Why does var in a loop with setTimeout print the wrong value?
"Because var is function-scoped, there is only ONE variable shared by all loop iterations and all setTimeout callbacks. By the time the callbacks execute, the loop has finished and the variable holds its final value. The fix is to use let, which is block-scoped and creates a new binding for each loop iteration, so each callback captures its own independent value."
Q5: Can you use const in a for...of loop?
"Yes. In for...of and for...in loops, a new binding is created on each iteration, so using const is valid — the value is assigned once per iteration and never reassigned within that iteration. However, you cannot use const in a regular for loop because the increment step (i++) would attempt to reassign the const variable, causing a TypeError."
Q6: What happens when you declare a variable with the same name using let in an inner block?
"This is called variable shadowing. The inner let creates a completely separate variable that shadows the outer one within its block scope. The outer variable is unaffected. This is safe with let and const because they are block-scoped. With var, declaring the same name inside a block does not shadow — it refers to the same variable and can overwrite the outer value."
Q7: Is let hoisted?
"Yes, let is hoisted — but unlike var, it is not initialized to undefined. It enters the Temporal Dead Zone. Proof: if you have a let variable in an inner block with the same name as an outer variable, accessing it before its declaration inside the block throws ReferenceError instead of reading the outer variable's value. This confirms the inner let was hoisted and the engine knows it exists — but cannot access it yet."
Q8: Why should we avoid var in modern JavaScript?
"var has several problematic behaviors: it leaks out of blocks (if, for, while) into function scope; it can be silently re-declared in the same scope, causing unintended overwrites; it is hoisted as undefined which can mask bugs; and when declared at global scope, it pollutes the window object. let and const fix all these issues with block scoping, TDZ, no re-declaration, and no window pollution."
Quick Recap
| Feature | var | let | const |
|---|---|---|---|
| Scope | Function / Global | Block | Block |
| Hoisting | Yes (undefined) | Yes (TDZ) | Yes (TDZ) |
| Re-declaration | ✅ Allowed | ❌ Not allowed | ❌ Not allowed |
| Re-assignment | ✅ Allowed | ✅ Allowed | ❌ Not allowed |
| Must Initialize | No | No | ✅ Yes |
| Global window property | ✅ Yes | ❌ No | ❌ No |
| Block scope | ❌ No | ✅ Yes | ✅ Yes |
| Before declaration | undefined | ReferenceError | ReferenceError |
| Recommended? | ❌ Avoid | ✅ When reassigning | ✅ Default choice |
Key Points to Remember
- var → function scoped, hoisted as undefined, can re-declare, leaks from blocks
- let → block scoped, hoisted in TDZ, cannot re-declare, can re-assign
- const → block scoped, hoisted in TDZ, cannot re-declare or re-assign, must initialize
- Block scope = any code inside { } — if, for, while, standalone blocks
- TDZ = Temporal Dead Zone — let/const exist but can't be accessed before their line
- const does NOT mean immutable — object/array contents can still change
- Use Object.freeze() for true immutability (shallow only)
- let in loops = new binding per iteration → closures work correctly
- var in loops = shared binding → all closures see the final value
- const in for...of = ✅ works (new binding per iteration)
- const in for loop = ❌ fails (increment tries to reassign)
- var at global scope → pollutes window object; let/const do not
- Modern best practice: const by default, let when needed, never var
- typeof is NOT safe from TDZ — only safe for truly undeclared variables
Keep coding, keep learning! See you in the next one!
Post a Comment