If you write JavaScript, you’ve probably used const. You might have heard of Object.freeze too. They sound similar. Both seem to “lock” something in place. But they work in very different ways.
Getting them mixed up causes bugs that are hard to track down. This article breaks down what each one does, shows you clear examples, and helps you know when to use which.
What Does const Do?
const creates a variable that you cannot reassign. That’s it.
It does not stop you from changing the contents of an object or array. It just stops you from pointing that variable to something else.
Example
const user = { name: "Alice", age: 25 };
user.name = "Bob"; // This works fine
console.log(user.name); // "Bob"
user = { name: "Charlie" }; // Error! Cannot reassign a const variable
So const locks the binding, not the value.
Think of it like a name tag glued to a box. You can’t move the name tag to a different box. But you can change what’s inside the box all you want.
What Does Object.freeze Do?
Object.freeze stops you from changing an object’s properties. You can still reassign the variable (if it’s not const), but you can’t modify what’s inside the frozen object.
Example
let config = { theme: "dark", lang: "en" };
Object.freeze(config);
config.theme = "light"; // Silently fails in normal mode
console.log(config.theme); // Still "dark"
config = { theme: "light" }; // This works, because config is `let`
Object.freeze locks the contents, not the variable.
Going back to our box: you can move the name tag to a new box. But you can’t change what’s inside the frozen one.
Using Both Together
Most of the time, you’ll want both. Use const to stop reassignment, and Object.freeze to stop property changes.
const settings = Object.freeze({ debug: false, version: "1.0" });
settings.debug = true; // Silently fails
settings = {}; // Error! Can't reassign const
console.log(settings.debug); // false
This gives you a truly immutable object for simple, flat data.
The Catch: Freeze is Shallow
Object.freeze only freezes the top level. Nested objects are still editable.
const app = Object.freeze({
name: "MyApp",
config: { debug: true }
});
app.name = "OtherApp"; // Fails, frozen
app.config.debug = false; // This WORKS! Nested object is not frozen
console.log(app.config.debug); // false
If you need deep freezing, you have to freeze each nested object yourself, or use a helper function.
Deep Freeze Example
function deepFreeze(obj) {
Object.keys(obj).forEach(key => {
if (typeof obj[key] === "object" && obj[key] !== null) {
deepFreeze(obj[key]);
}
});
return Object.freeze(obj);
}
const app = deepFreeze({
name: "MyApp",
config: { debug: true }
});
app.config.debug = false; // Now this fails too
console.log(app.config.debug); // true
Does Freeze Work in Strict Mode?
In normal mode, trying to change a frozen object fails silently. No error is thrown. This can hide bugs.
In strict mode, it throws a TypeError. That’s usually what you want during development.
"use strict";
const config = Object.freeze({ env: "prod" });
config.env = "dev"; // TypeError: Cannot assign to read only property
Always use strict mode to catch these issues early.
Quick Comparison Table
| Feature | const |
Object.freeze |
|---|---|---|
| Blocks reassignment | Yes | No |
| Blocks property changes | No | Yes |
| Works on arrays | Yes | Yes |
| Deep freeze | N/A | No (shallow only) |
| Throws in strict mode | Yes | Yes |
Real World Use Cases
Use const when: You want to make sure a variable always points to the same thing. This is good practice for most variables, even when you plan to mutate the object.
const users = [];
users.push("Alice"); // Fine, you're not reassigning
Use Object.freeze when: You have config data, constants, or lookup tables that should never change at runtime.
const STATUS = Object.freeze({
PENDING: "pending",
ACTIVE: "active",
CLOSED: "closed"
});
Use both when: You want a fully locked object with no reassignment and no property changes.
FAQs
Q: Does const make an object immutable?
No. const only stops you from reassigning the variable. The object’s properties can still be changed.
Q: Does Object.freeze prevent reassignment?
No. If the variable uses let or var, you can still point it to a new object. Freeze only protects the contents.
Q: Can I freeze an array?
Yes. Object.freeze works on arrays too. After freezing, you can’t push, pop, or modify elements.
const colors = Object.freeze(["red", "green", "blue"]);
colors.push("yellow"); // TypeError in strict mode
Q: Is Object.freeze permanent?
Yes. Once an object is frozen, it cannot be unfrozen. There is no Object.unfreeze.
Q: Does freeze affect performance?
For most apps, the difference is too small to matter. Frozen objects can sometimes help JavaScript engines optimize code, but don’t freeze everything just for speed.
Q: How do I deeply freeze a nested object?
Write a recursive function that freezes each nested object, or use a library like deep-freeze.
Q: Should I always use const instead of let?
Use const by default. Switch to let only when you need to reassign the variable.
Summary
const and Object.freeze solve different problems. const stops you from reassigning a variable. Object.freeze stops you from changing an object’s properties.
For truly locked data, use both. And remember, freeze is shallow, so nested objects still need to be frozen separately.
Once you understand this, you’ll write cleaner, safer JavaScript and avoid a whole class of subtle bugs.
Why Commerce Analytics Fails at Scale