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" } }
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" } }
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
-
Shallow Freeze:
- Suitable when only the top-level properties need to be immutable.
- Examples: Configurations where nested properties are managed independently.
-
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);
}
This prevents infinite recursion for cyclic references.
Top comments (0)