JavaScript has three ways to declare a variable. You met each one early on; now that you understand scope and hoisting, this lesson puts them side by side so you can choose correctly and read older code with confidence.
| var | let | const | |
|---|---|---|---|
| Scope | Function | Block | Block |
| Reassign | Yes | Yes | No |
| Redeclare in same scope | Yes (silently) | No | No |
| Use before declaring | undefined | Error | Error |
| Must initialize | No | No | Yes |
| Global becomes window property | Yes | No | No |
| Introduced | 1995 | 2015 (ES6) | 2015 (ES6) |
function checkout(items) {
for (var i = 0; i < items.length; i++) {
var price = items[i];
}
console.log(i, price); // both still exist after the loop
}
checkout([4, 9, 2]);
With let, both lines would throw an error, because i and price would stay inside the loop where they belong.
var total = 100;
// ...200 lines later, someone reuses the name...
var total = 0; // no warning; the first total is gone
let count = 1;
let count = 2; // SyntaxError: Identifier 'count' has already been declared
In a browser, a top-level var becomes a property of window, where it can collide with built-in names:
var appName = "Lab";
let appMode = "dev";
console.log(window.appName); // "Lab"
console.log(window.appMode); // undefined
var name = 42; at the top level in a browser does not give you the number 42. window.name is a built-in property that always stores a string, so you get "42". With let you get the number you expect.
Covered in Code Blocks: var gives every loop pass the same shared variable, so timers and event handlers created in the loop all see its final value. let gives each pass its own.
let a = b = "unknown"; looks like it declares two variables, but let only applies to a. The b = "unknown" part assigns to an undeclared b, which quietly becomes an automatic global (or a ReferenceError in strict mode). W3Schools uses exactly this line in its var/let/const example. Declare each variable separately: let a = "unknown"; let b = "unknown";.
const. Most values never need to be reassignedletvar in new codeconst TAX = 0.08; // never changes
const cart = []; // contents change, but it is always the same array
let subtotal = 0; // reassigned as items are added
for (const price of [5, 12, 3]) { // const works here: each pass gets a new price
cart.push(price);
subtotal += price;
}
console.log(cart, subtotal, (subtotal * (1 + TAX)).toFixed(2));
const in for...of works because each pass creates a new variable. In a classic for (let i = 0; ...; i++) loop you need let, since i++ reassigns it.
You will still meet var in tutorials, Stack Overflow answers, and older projects. When you do, read it as "function-scoped, hoisted as undefined." When updating such code, swapping var for let or const is usually safe, but check that nothing relied on the variable leaking out of a block.
Which keyword should be your default choice?
varletconstconst, and switch to let only when the variable really needs to be reassigned. Avoid var in new code.What does this log?
if (true) {
var a = 1;
let b = 2;
}
console.log(typeof a, typeof b);
number undefined. var a leaked out of the block; let b did not. (typeof on a name that does not exist gives "undefined" instead of throwing an error.)What is wrong with for (const i = 0; i < 3; i++)?
i++ reassigns i, which const forbids: TypeErrorconst cannot be used in a for header at alli++ throws TypeError: Assignment to constant variable. Use let for counters. (const is fine in for...of, where each pass gets a brand-new variable.)checkout with let and read the new errorsvar, then with letwindow.x after var x = 1 with window.y after let y = 1