Skip to Content
Course content

48: Object.freeze and Immutability Patterns

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think of Object.freeze like a legal contract that's been signed, notarized, and filed with the court. Before the signing, you can move clauses around, change the payment terms, or add new requirements. But the moment that notary stamps it? It's locked. If you try to take a pen and cross out a line to change the price, the contract doesn't magically change—it just becomes a defaced document, and the court will ignore your changes.

In JavaScript, we map this directly to how we handle data:

  • The Draft: A standard JavaScript object where you can add, delete, or change properties.
  • The Notary Stamp: Calling Object.freeze(yourObject).
  • The Defaced Document: Trying to assign a new value to a frozen property. In strict mode, JavaScript will throw an error; in non-strict mode, it'll just silently fail.
  • The Supplemental Agreement: Instead of editing the original, you create a new object that copies the old one but adds the specific change you need.

Locking the Doors with Object.freeze

You'll most often use this when you have a set of constants or a configuration object that must not change while the app is running. I've seen way too many bugs where a developer accidentally mutated a global config object in one function, which then broke five other unrelated features. It's a nightmare to debug.

"use strict";

const API_CONFIG = Object.freeze({
    baseUrl: "https://api.myapp.com/v1",
    timeout: 5000,
    retries: 3
});

// This will throw a TypeError because we're in strict mode
API_CONFIG.timeout = 10000; 

// This will also fail (silently or with an error)
API_CONFIG.newSetting = "enabled"; 

By freezing the object, you're telling other developers (and your future self), "This data is a source of truth. Do not touch it."

The Shallow Freeze Trap

Here is where a lot of people get tripped up: Object.freeze is shallow. It only locks the immediate properties of the object. If one of those properties is another object or an array, that nested object is still fair game. It's like notarizing a folder; you can't replace the folders inside, but you can still reach into a folder and scribble on the papers inside it.

const APP_STATE = Object.freeze({
    version: "1.0.0",
    settings: {
        theme: "dark",
        notifications: true
    }
});

APP_STATE.version = "2.0.0"; // Fails (Frozen)
APP_STATE.settings.theme = "light"; // Works! (The nested object wasn't frozen)

If you need a "Deep Freeze," you'd have to write a recursive function that freezes every object it finds inside the root object. In most professional projects, however, we handle this by adopting an immutability pattern instead of trying to freeze everything.

The Immutability Workflow

In modern JavaScript—especially if you ever touch React or Redux—we rarely "freeze" everything. Instead, we treat objects as if they were frozen. When we need to change something, we don't mutate the original; we create a copy with the updated value using the spread operator (...).

I prefer this approach because it gives you a history of your state. If you mutate an object, the previous version is gone forever. If you create a new object, you can keep the old one for undo/redo functionality or debugging.

const user = {
    id: 1,
    name: "Alex",
    email: "alex@example.com"
};

// Instead of: user.email = "new@example.com";
// Do this:
const updatedUser = { 
    ...user, 
    email: "new@example.com" 
};

console.log(user.email);        // "alex@example.com" (Original preserved)
console.log(updatedUser.email); // "new@example.com" (New version created)

This pattern—combining Object.freeze for true constants and the spread operator for state updates—is the gold standard for writing predictable, bug-free JavaScript.




📋 Practical Task

Exercise: The Immutable Game Engine Config

You are building a game engine. The core physics rules must be immutable so that the game logic remains consistent, but the player's session settings should be updatable using immutability patterns.

Your Task:

  1. Create a constant object called PHYSICS_RULES containing gravity: -9.81 and friction: 0.5. Use Object.freeze to ensure these cannot be changed.
  2. Create a playerSession object with username: "Player1", level: 1, and inventory: ["Sword"].
  3. Write a function called updateLevel(session, newLevel). This function must not mutate the original session object. Instead, it should return a new object with the updated level using the spread operator.
  4. Try to change PHYSICS_RULES.gravity and verify (via console.log) that it did not change.
  5. Call updateLevel and verify that the original playerSession remains at level 1, while the returned object is at the new level.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.