Episode 3 of 11
The Let Keyword
Understand let — block-scoped variables, the temporal dead zone, and how let fixes common var pitfalls.
The Let Keyword
let declares a block-scoped variable that can be reassigned. It fixes the scoping problems of var and is the go-to choice when you need a variable whose value changes.
Basic Syntax
let score = 0;
score = 10; // ✅ Reassignment is allowed
score = score + 5; // ✅
console.log(score); // 15
let vs var — Block Scoping
// var leaks out of blocks
for (var i = 0; i < 3; i++) {
// ...
}
console.log(i); // 3 ← var leaked out of the for block!
// let stays in its block
for (let j = 0; j < 3; j++) {
// ...
}
console.log(j); // ❌ ReferenceError: j is not defined ← safe!
The Classic var Bug
// The infamous closure-in-loop problem:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 ← All see the same i (3 after loop ends)
// Fixed with let:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2 ← Each iteration gets its own i
With let, each loop iteration creates a new scope with its own i. With var, there's only one i shared across all iterations.
The Temporal Dead Zone (TDZ)
// var is hoisted and initialized to undefined
console.log(a); // undefined (no error)
var a = 10;
// let is hoisted but NOT initialized
console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization
let b = 10;
The time between entering the scope and the let declaration is called the Temporal Dead Zone. Accessing the variable during this time throws an error — making bugs easier to catch.
No Re-declaration
// var allows re-declaration (silently overwrites!)
var name = "Alice";
var name = "Bob"; // No error — silently replaced!
// let does NOT allow re-declaration
let age = 25;
let age = 30; // ❌ SyntaxError: Identifier 'age' has already been declared
let in Different Scopes
let x = 10; // Global scope
if (true) {
let x = 20; // Block scope — different variable!
console.log(x); // 20
}
console.log(x); // 10 — the outer x is unchanged
The inner let x is a completely separate variable that shadows the outer one.
var vs let vs const — Complete Comparison
| Feature | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisted | Yes (initialized undefined) | Yes (but TDZ) | Yes (but TDZ) |
| Re-declaration | ✅ Allowed | ❌ Error | ❌ Error |
| Reassignment | ✅ Allowed | ✅ Allowed | ❌ Error |
| Must initialize | No | No | Yes |
When to Use let
| Situation | Use |
|---|---|
Loop counter (for, while) | let |
| Value reassigned later | let |
| Accumulator or running total | let |
| Value never changes | const (prefer this!) |
The Modern Rule
// ✅ Default to const
const apiUrl = "https://api.example.com";
const users = [];
// ✅ Use let only when you need to reassign
let isLoading = true;
// ... some async work ...
isLoading = false;
// ❌ Never use var in modern code
var old = "avoid this";
Key Takeaways
letis block-scoped and can be reassigned (unlikeconst)- Fixes the loop closure bug that plagued
var - The Temporal Dead Zone prevents access before declaration
- Cannot be re-declared in the same scope
- Modern rule: use
constby default,letwhen reassignment is needed, nevervar