In the let video, let was a whiteboard. Picture it hanging inside one room, and the walls of that room are the curly braces. A var whiteboard ignores the walls. Write on it inside the room, and everyone outside can see it too.
Why var acts differently
var is older than block scope. It only respects the walls of a function. The braces of an if, a for loop or a plain block don't hold it in. let and const arrived in 2015 to fix that.
function makeSnack() {
var fruit = "apple";
return fruit;
}
console.log(makeSnack()); // prints: apple
console.log(typeof fruit); // prints: undefined
Here the function walls do their job. fruit exists inside makeSnack, and outside it there's no such name (typeof reports "undefined" for a name that was never made). Every other kind of curly brace is see-through to var.
It leaks out of blocks
if (true) {
var color = "teal";
}
console.log(color); // prints: teal
The variable was made inside the if block, but you can still use it outside. With let, that last line would throw ReferenceError: color is not defined.
An error sounds bad, but here it helps you. It tells you right away that you used the variable in the wrong place, instead of letting the bug hide.
Leaking shows up a lot in loops. A var loop counter is still hanging around after the loop ends.
for (var i = 0; i < 3; i++) {}
console.log(i); // prints: 3It lets you declare a name twice
var name = "Bitsy";
var name = "Bob";
console.log(name); // prints: Bob
No warning at all. The second line just replaces the first. In a long file, that's an easy way to overwrite something you still needed.
let and const refuse with SyntaxError: Identifier 'name' has already been declared. That name is taken.
The twist: hoisting
Hoisting means lifted to the top. Before your code runs, JavaScript sets up every var name at the top of its function (or file), but leaves the value behind on its own line. So if you use a var too early, you don't get an error. You get undefined.
console.log(cookie); // prints: undefined
var cookie = "yum";
console.log(cookie); // prints: yum
let and const are hoisted too, but they stay locked until their line runs. Touch one before that and you get ReferenceError: Cannot access 'cookie' before initialization. That error catches the bug early, which is what you want.
What to use instead
In new code, use const. If the value has to change, use let. You will still see var in older tutorials, libraries and answers online, so it helps to recognize it, but you don't need to write it yourself.
When you copy an old example that uses var, change it as you paste it in. Most of the time const works straight away. If JavaScript then complains that you assigned to a constant, switch that one to let.
Rule of thumb
Don't use var. Use const, or let when the value changes.
Swapping every var for let in old code without looking. If the code relied on a variable leaking out of a block, the swap turns it into a ReferenceError. Move the declaration above the block first, then change it to let or const.
Check yourself
The var name is hoisted to the top, but its value stays on its own line. So the name exists early with the value undefined.