Remember Grandpa's old box, var, from Grade 1? We said it had some quirks related to scope. Here's the biggest one: var ignores block scope. It only respects function scope. So a var created inside an if block or a loop leaks out into the surrounding function (or the global scope):
if (true) {
var leaky = "I escaped!";
let polite = "I stay inside.";
}
console.log(leaky);
console.log(typeof polite);
It prints
I escaped! undefined
for (var j = 0; j < 3; j++) {
// ...
}
console.log(`After the loop, j is ${j}`);
It prints
After the loop, j is 3
The loop is over, but j is still hanging around like a guest who won't leave the party. This leaking caused countless bugs over the years, and it's the main reason let and const were invented.
Here's a classic that caught out JavaScript developers for years. It uses setTimeout, which runs a function later, after a delay. (You'll learn all about it in College.)
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log(`var: ${i}`), 10);
}
for (let k = 1; k <= 3; k++) {
setTimeout(() => console.log(`let: ${k}`), 20);
}
It prints
var: 4 var: 4 var: 4 let: 1 let: 2 let: 3
With var, there's only one i for the entire loop. By the time the delayed functions run, the loop has finished and i is 4, so they all print 4. With let, each trip around the loop gets its own fresh k, so each function remembers its own value. Just one more reason to always use let and const!