Bitsy Explains
Home/JavaScript, Explained Like You're Five/Lesson 1

let vs const in JavaScript

let and const both create named values. With let you can give the name a new value later, with const you can't. Picking the right one makes your code easier to trust.

Lesson 1 of 203 min readVideo
Video thumbnail: let vs const Watch the 90-second video
Explain like I'm five

Think of let as a whiteboard with a label on top. You can erase what's under the label and write something new. const is a name carved into a trophy. Once it's carved it stays, and you can't swap it for a different trophy.

let: the whiteboard

Use let when a value needs to change over time, like the score in a game. You create the variable once, then give it new values with a plain =.

let score = 5;
console.log(score); // prints: 5
score = 10;
console.log(score); // prints: 10

You only write let the first time. After that the name already exists, so you just assign to it.

const: the trophy

A const gets one value and keeps it. Try to give it a new one and JavaScript stops with a TypeError.

const name = "Bitsy";
name = "Bob"; // TypeError: Assignment to constant variable.

A const also needs its value right away. Writing const age; on its own is a SyntaxError (Missing initializer in const declaration). Write const age = 7; instead.

So why have both? A const is a promise that this name will never get a new value. When you read your code later, or someone else does, there are fewer surprises. If you see const, you don't have to hunt for the line where it changes.

Block scope

Both let and const only exist inside the curly braces { } where you made them. The code between a pair of braces is called a block, and this rule is called block scope. An if, a loop or a plain pair of braces each make a block.

const pet = "cat";
if (true) {
  let snack = "cookie";
  console.log(pet, snack); // prints: cat cookie
}
console.log(pet); // prints: cat

pet was made outside the block, so it works in both places. snack only lives inside the braces. Adding console.log(snack) after the closing brace would stop the program with ReferenceError: snack is not defined.

This is helpful. A name you only need for a few lines disappears when you're done with it, so it can't clash with another name somewhere else in your program.

The twist: a const array can still change inside

A const locks the name. It doesn't lock what the name points to. An array is a list in square brackets, and if you make one with const you can still add to it, remove from it or change its items. What you can't do is point the name at a whole new array.

const toys = ["teddy"];
toys.push("robot");
console.log(toys); // prints: [ 'teddy', 'robot' ]

Writing toys = ["ball"]; would throw the same TypeError as before. Objects work the same way, so the properties of a const object can still change.

If you want the inside locked too, use Object.freeze. After that, push throws an error and the array stays as it was.

const snacks = Object.freeze(["apple"]);
try {
  snacks.push("cookie");
} catch (err) {
  console.log(err.name); // prints: TypeError
}
console.log(snacks); // prints: [ 'apple' ]

Object.freeze only locks the top level. An object stored inside a frozen array can still change.

Rule of thumb

Default to const, and use let only when the value must change.

Common mistake

Starting every variable with let out of habit. Write const first and switch to let only when you really need to give the name a new value, like a counter that goes up.

Check yourself

Which of these causes an error?