Immutability Helper - Problem
The Immutability Challenge
In modern JavaScript development, immutability is a cornerstone principle that prevents unexpected side effects and makes code more predictable. However, creating modified copies of complex nested objects can be tedious and error-prone.
Your task is to implement an
• Accept any JSON object or array in its constructor
• Provide a
• Return a new object with changes applied, while keeping the original untouched
• Use JavaScript Proxy to create an illusion of direct mutation
Example:
The mutator function receives a proxied version of the object that tracks all changes without affecting the original. Your implementation must handle nested objects and arrays while maintaining immutability.
In modern JavaScript development, immutability is a cornerstone principle that prevents unexpected side effects and makes code more predictable. However, creating modified copies of complex nested objects can be tedious and error-prone.
Your task is to implement an
ImmutableHelper class that provides a clean, intuitive API for creating modified copies of immutable objects. The class should:• Accept any JSON object or array in its constructor
• Provide a
produce method that takes a mutator function• Return a new object with changes applied, while keeping the original untouched
• Use JavaScript Proxy to create an illusion of direct mutation
Example:
const originalObj = {x: 5, nested: {y: 10}};
const helper = new ImmutableHelper(originalObj);
const newObj = helper.produce((proxy) => {
proxy.x = proxy.x + 1;
proxy.nested.y = 20;
});
console.log(originalObj); // {x: 5, nested: {y: 10}} - unchanged!
console.log(newObj); // {x: 6, nested: {y: 20}} - modified copyThe mutator function receives a proxied version of the object that tracks all changes without affecting the original. Your implementation must handle nested objects and arrays while maintaining immutability.
Input & Output
basic_mutation.js — Basic Property Change
$
Input:
const originalObj = {x: 5, y: 10};
const helper = new ImmutableHelper(originalObj);
const newObj = helper.produce((proxy) => {
proxy.x = proxy.x + 1;
});
›
Output:
originalObj: {x: 5, y: 10}
newObj: {x: 6, y: 10}
💡 Note:
The proxy intercepts the assignment to `proxy.x` and creates a new object with the modified value while keeping the original unchanged.
nested_mutation.js — Nested Object Modification
$
Input:
const originalObj = {user: {name: 'John', age: 30}, count: 5};
const helper = new ImmutableHelper(originalObj);
const newObj = helper.produce((proxy) => {
proxy.user.age = 31;
proxy.count = 6;
});
›
Output:
originalObj: {user: {name: 'John', age: 30}, count: 5}
newObj: {user: {name: 'John', age: 31}, count: 6}
💡 Note:
The proxy handles nested object access by creating proxies for nested objects, allowing deep mutations while preserving immutability of the original structure.
array_mutation.js — Array Modification
$
Input:
const originalArr = [1, 2, {value: 3}];
const helper = new ImmutableHelper(originalArr);
const newArr = helper.produce((proxy) => {
proxy[0] = 10;
proxy[2].value = 30;
});
›
Output:
originalArr: [1, 2, {value: 3}]
newArr: [10, 2, {value: 30}]
💡 Note:
Arrays are handled just like objects, with array indices treated as properties. The proxy creates new arrays and objects only for the paths that are modified.
Visualization
Tap to expand
Understanding the Visualization
1
Original Object Tree
Start with the original immutable object structure
2
Proxy Wrapper
Wrap the object in a Proxy that intercepts all property access
3
Mutation Detection
When a property is modified, create a copy-on-write for that path
4
Structural Sharing
Unchanged parts of the object tree are shared between original and result
Key Takeaway
🎯 Key Insight: JavaScript Proxy enables transparent immutability by intercepting mutations and applying copy-on-write semantics, creating efficient immutable updates with minimal memory overhead.
Time & Space Complexity
Time Complexity
O(m * log d)
Where m is the number of mutations and d is the average depth. Log factor comes from path traversal optimization.
⚡ Linearithmic
Space Complexity
O(m)
Only allocates memory for actually modified objects plus minimal proxy overhead.
✓ Linear Space
Constraints
- The input object will be a valid JSON object or array
-
The mutator function will always return
undefined - The mutator will never access non-existent keys
- The mutator will never delete keys or call methods on objects
- The original object must never be modified
- Maximum object depth: 100 levels
- Maximum number of properties per object: 1000
💡
Explanation
AI Ready
💡 Suggestion
Tab
to accept
Esc
to dismiss
// Output will appear here after running code