
When you see const in JavaScript, it’s not just about “constant” values in the classical sense. Unlike languages like C or Java where const means the value can never change, in JavaScript, it is a bit more nuanced.
First off, const declares a read-only reference to a value. This means once you assign something to a const variable, you can’t reassign it. But—and that’s the kicker—if that value is an object or an array, the contents inside can still mutate.
const arr = [1, 2, 3]; arr.push(4); // perfectly fine console.log(arr); // [1, 2, 3, 4] arr = [5, 6, 7]; // TypeError: Assignment to constant variable.
The above example shows that the variable arr itself is locked to the same reference, but the object or array it points to remains mutable. That’s a subtle detail that trips a lot of developers new to ES6.
Another important point: const must be initialized at the time of declaration. You can’t declare a const and assign it later.
const name; // SyntaxError: Missing initializer in const declaration const name = "Jeff"; // perfectly valid
Scoping with const works just like let – block-scoped and not hoisted like var. This makes it much easier to avoid the typical pitfalls of variable hoisting and unexpected globals.
Of note, since const declarations are block scoped, inside loops you can have new bindings per iteration, which is a far cry from the old var funk:
for (const i = 0; i < 3; i++) {
console.log(i);
}
// This loop will actually error out because i is const and you are trying to reassign i.
If you want a loop counter, const isn’t the right tool. But for fixed values inside blocks that must never be reassigned, it’s perfect.
2 Pack Case with Tempered Glass Screen Protector for Apple Watch SE3(2025) SE2 Series 6/5/4/SE 40mm,JZK Slim Guard Bumper Full Coverage Hard PC Protective Cover Ultra-Thin Cover for iWatch 40mm,Clear
$5.93 (as of June 2, 2026 22:39 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Best practices for using constants in your code
When defining constants in your code, prefer using const whenever you know the identifier should not be reassigned. It explicitly signals intent and prevents accidental reassignment bugs, making your code more predictable and easier to maintain.
For primitive values like numbers, strings, and booleans that should never change, const is the ideal choice:
const MAX_RETRIES = 5; const API_ENDPOINT = "https://api.example.com/v1/data"; const IS_PRODUCTION = true;
Using uppercase naming conventions for such truly constant values improves readability and communicates to other developers that these values are meant to remain unchanged.
When working with objects or arrays that conceptually should not change—like configuration objects or lookup tables—you can declare them const but still be mindful that their internal contents can be mutated. If you want to prevent mutation of the data inside, consider freezing the object:
const CONFIG = Object.freeze({
version: "1.0.0",
maxConnections: 10
});
CONFIG.version = "2.0.0"; // silently ignored in non-strict mode, TypeError in strict mode
This pattern ensures that your configuration object’s properties remain immutable at runtime, adding an extra layer of protection.
Remember that Object.freeze() is shallow, so nested objects within the frozen object remain mutable unless you recursively freeze them as well:
const deepFreeze = (obj) => {
Object.getOwnPropertyNames(obj).forEach(prop => {
if (typeof obj[prop] === "object" && obj[prop] !== null) {
deepFreeze(obj[prop]);
}
});
return Object.freeze(obj);
};
const NESTED_CONFIG = deepFreeze({
settings: {
theme: "dark",
languages: ["en", "es"]
}
});
NESTED_CONFIG.settings.theme = "light"; // TypeError in strict mode
Avoid using var in new codebases. It lacks block scoping, leading to confusing bugs (like hoisting and unintended globals) that const and let were designed to eliminate.
Another practical best practice for constants is to avoid reusing const in loops that require reassignment. If your loop counter or accumulator changes per iteration, use let instead.
for (let i = 0; i < 10; i++) {
console.log(i);
}
Keep in mind that const does not create true immutability by default—it only ensures that the variable identifier cannot be reassigned to a different value or reference. The key is to combine const with immutability patterns like Object.freeze(), immutable data libraries, or functional programming techniques.
Finally, favor separating concerns by defining constants in dedicated modules or configuration files when values need to be shared across your codebase. This way, updating constants is more manageable, and you reduce magic numbers or strings scattered throughout your logic.
