const was added to JavaScript in ES6 (2015), alongside let. It declares a variable that cannot be reassigned. Use it whenever a variable should keep pointing at the same value, which turns out to be most of the time. When someone reads const in your code, they instantly know that name will not be pointed at anything else.
The rules for const:
TypeErrorconst empty; on its own and run it. How is this error different from the one in step 1?const settings = {theme: "dark"}. Change settings.theme = "light" and log it. Then try settings = {}const team = ["Ana"]. Add two names with push, change the first name, and log it. Then explain in your notes why none of that was an errorRules 3 and 4 work just as you learned in the JS Let lesson. This lesson focuses on what is new: rules 1 and 2, and what "cannot be reassigned" really means for arrays and objects.
Once a const has a value, any attempt to put a new value in it throws an error. That includes updates based on its own value:
const PI = 3.141592653589793;
PI = 3.14; // error
PI = PI + 10; // also an error
This is the point of const: it protects values that should never change from being overwritten by accident, whether by a typo, a copy-paste, or someone else's code.
With let you can declare now and assign later. With const you cannot, because there would be no way to ever give it a value:
// Correct
const PI = 3.14159265359;
// Incorrect
const PI;
PI = 3.14159265359;
The name const is a little misleading. It does not make the value constant. It makes the reference constant: the name is permanently attached to one particular value.
Think of a label glued to a box. const glues the label on, so you can never peel it off and stick it on a different box. But nothing stops you opening the box and changing what is inside.
For simple values like numbers, strings, and booleans, there is nothing "inside" to change, so the value really is fixed. Arrays and objects are different: they are containers. So with a const array or object:
| You CAN | You can NOT |
|---|---|
| Change an element of a constant array | Reassign a constant array |
| Add or remove array elements | Reassign a constant object |
| Change, add, or remove object properties | Reassign a constant number, string, or boolean |
const cars = ["Saab", "Volvo", "BMW"];
cars[0] = "Toyota"; // change an element: fine
cars.push("Audi"); // add an element: fine
console.log(cars);
cars = ["Kia", "Ford"]; // replace the whole array: error
const car = {type: "Fiat", model: "500", color: "white"};
car.color = "red"; // change a property: fine
car.owner = "Johnson"; // add a property: fine
console.log(car);
car = {type: "Volvo"}; // replace the whole object: error
const array or object is protected from changes. It is not; only the name is locked. If you truly need the contents locked too, Object.freeze(car) does that, and any later changes to it are ignored. You will rarely need it as a beginner, but now you know the difference.
Always declare a variable with const when you know it should not be reassigned. In practice that means using const when you create:
Switch to let only when you know the value must be replaced, such as a counter, a running total, or something that updates as the user interacts with the page.
// const: the name always points at the same thing
const TAX_RATE = 0.08;
const MAX_RETRIES = 3;
const cart = []; // contents change, the cart does not
const player = {name: "Ana"};
// let: the value gets replaced
let retryCount = 0;
let currentUser = null;
let isLoading = true;
UPPER_SNAKE_CASE is used for fixed settings known before the program runs (TAX_RATE, MAX_RETRIES). Everything else declared with const, like cart and player, uses normal camelCase. Capitals signal "this is a setting, never changes"; they are not required just because you used const.
const has block scope, just like let. A const declared inside a block is a separate variable from one with the same name outside it:
const x = 10;
{
const x = 2;
console.log(x); // the inner x
}
console.log(x); // the outer x, unchanged
And like let, a const declared in a block does not exist outside it:
{
const limit = 100;
}
console.log(limit);
You cannot turn an existing var or let into a const, or declare the same const twice, in the same scope:
var x = 2; // Allowed
const x = 2; // Not allowed
{
let x = 2; // Allowed
const x = 2; // Not allowed
}
{
const x = 2; // Allowed
const x = 2; // Not allowed
}
Once a const exists, nothing in that same scope can reassign or redeclare it, with any keyword:
const x = 2; // Allowed
x = 2; // Not allowed (reassign, even to the same value)
var x = 2; // Not allowed
let x = 2; // Not allowed
const x = 2; // Not allowed
Declaring a const with the same name in a different block is allowed, because each block has its own scope:
const x = 2; // Allowed
{
const x = 3; // Allowed
}
{
const x = 4; // Allowed
}
Like let, a const is hoisted to the top of its block but not initialized. Using it before its declaration line puts it in the temporal dead zone and throws an error, where a var would quietly give undefined:
console.log(carName);
const carName = "Volvo";
The fix is the same habit as with let: declare first, then use. Hoisting gets its own lesson later (JS Hoisting).
| Feature | var | let | const |
|---|---|---|---|
| Scope | Function or global | Block | Block |
| Reassign | Yes | Yes | No |
| Redeclare | Yes (silently) | No | No |
| Must assign on declare | No | No | Yes |
| Used before declared | undefined | ReferenceError | ReferenceError |
for (let i = 0; i < 3; i++). Writing const i there instead throws TypeError: Assignment to constant variable. because i++ reassigns i every time around the loop. Loop counters are the classic case for let.
Does this work? If so, what is logged?
const scores = [80, 90];
scores.push(100);
console.log(scores);
[80, 90, 100]. push changes what is inside the array; it does not reassign scores.Does this work?
const lives = 3;
lives--;
TypeError: Assignment to constant variable. lives-- is shorthand for lives = lives - 1, which is a reassignment. Anything that changes over time, like lives, should be let.What does this log?
const level = 1;
{
const level = 5;
}
console.log(level);
1. The inner level is a separate constant that only exists inside its block. This is allowed because it is a different scope.const SITE_NAME = "JS Lab", then try to reassign it. Read the TypeErrorconst empty; on its own and read the error. How is it different from the one in step 1?const settings = {theme: "dark"}. Change settings.theme = "light" and log it. Then try settings = {}const team = ["Ana"]. Add two names with push, change the first name, and log it. Then explain in your notes why none of that was an error