DEV Community

Cover image for JavaScript Object - Shallow freeze vs Deep freeze
Syed Ammar
Syed Ammar

Posted on

JavaScript Object - Shallow freeze vs Deep freeze

The difference between shallow freeze and deep freeze lies in how the freezing behavior is applied to nested objects. Here’s a breakdown of the two concepts:


1. Shallow Freeze

  • Definition: Freezes only the top-level properties of an object.
  • Behavior:
    • Prevents adding, removing, or modifying the top-level properties.
    • Does not freeze nested objects; they remain mutable.
  • Example:
const shallowObject = {
    name: "Alice",
    details: { age: 25, city: "New York" },
};

Object.freeze(shallowObject);

// Top-level properties are immutable
shallowObject.name = "Bob"; // Ignored
shallowObject.newProp = "test"; // Ignored

// Nested objects are still mutable
shallowObject.details.age = 30; // Allowed

console.log(shallowObject);
// Output: { name: "Alice", details: { age: 30, city: "New York" } }
Enter fullscreen mode Exit fullscreen mode

2. Deep Freeze

  • Definition: Freezes the object along with all its nested objects and arrays, recursively.
  • Behavior:
    • Ensures that no part of the object (top-level or nested) can be modified.
  • Example:
const deepObject = {
    name: "Alice",
    details: { age: 25, city: "New York" },
};

// Deep freeze function
function deepFreeze(object) {
    const propertyNames = Object.getOwnPropertyNames(object);
    for (const name of propertyNames) {
        const value = object[name];
        if (value && typeof value === 'object') {
            deepFreeze(value); // Recursively freeze
        }
    }
    return Object.freeze(object);
}

deepFreeze(deepObject);

// Neither top-level nor nested properties can be changed
deepObject.name = "Bob"; // Ignored
deepObject.details.age = 30; // Ignored

console.log(deepObject);
// Output: { name: "Alice", details: { age: 25, city: "New York" } }
Enter fullscreen mode Exit fullscreen mode

Comparison Table

Feature Shallow Freeze Deep Freeze
Scope Only freezes top-level properties. Freezes top-level and nested objects.
Nested Object Mutability Mutable. Immutable.
Implementation Object.freeze(object). Custom recursive function with Object.freeze().
Example Mutation Modifications to nested objects are allowed. No modifications allowed at any level.

Use Cases

  1. Shallow Freeze:

    • Suitable when only the top-level properties need to be immutable.
    • Examples: Configurations where nested properties are managed independently.
  2. Deep Freeze:

    • Ideal when complete immutability is required for the entire object hierarchy.
    • Examples: Ensuring data consistency for deeply nested objects in state management.

Considerations

  • Performance:
    • Deep freezing can be computationally expensive for large or deeply nested objects.
  • Cyclic References:
    • If the object contains circular references, you'll need to track visited objects to avoid infinite recursion.

Handling Cyclic References

To handle cyclic references, you can maintain a WeakSet of visited objects:

function deepFreeze(object, visited = new WeakSet()) {
    // If the object is already visited, return it
    if (visited.has(object)) return object;

    // Add the object to the visited set
    visited.add(object);

    // Retrieve property names
    const propertyNames = Object.getOwnPropertyNames(object);

    // Freeze each property
    for (const name of propertyNames) {
        const value = object[name];
        if (value && typeof value === 'object') {
            deepFreeze(value, visited);
        }
    }

    return Object.freeze(object);
}
Enter fullscreen mode Exit fullscreen mode

This prevents infinite recursion for cyclic references.

Top comments (0)