创建带有微小修改的不可变对象的克隆副本是一个繁琐的过程。请你编写一个名为 ImmutableHelper
的类,作为满足这一要求的工具。构造函数接受一个不可变对象 obj
,该对象将是一个 JSON 对象或数组。
该类有一个名为 produce
的方法,它接受一个名为 mutator
的函数。该函数返回一个新的对象,它与原始对象相似,但应用了这些变化。
mutator
函数接受 obj
的 代理 版本。函数的使用者可以(看起来)对该对象进行修改,但原始对象 obj
实际上没有被改变。
例如,用户可以编写如下代码:
const originalObj = {"x": 5}; const helper = new ImmutableHelper(originalObj); const newObj = helper.produce((proxy) => { proxy.x = proxy.x + 1; }); console.log(originalObj); // {"x": 5} console.log(newObj); // {"x": 6}
mutator
函数的属性:
- 它始终返回
undefined
。 - 它永远不会访问不存在的键。
- 它永远不会删除键(
delete obj.key
)。 - 它永远不会在代理对象上调用方法(
push
、shift
等)。 - 它永远不会将键设置为对象(
proxy.x = {}
)。
关于如何测试解决方案的说明:解决方案验证器仅分析返回结果与原始 obj
之间的差异。进行完全比较的计算开销太大。此外,对原始对象进行的任何变更都将导致答案错误。
示例 1:
输入: obj = {"val": 10}, mutators = [ proxy => { proxy.val += 1; }, proxy => { proxy.val -= 1; } ] 输出: [ {"val": 11}, {"val": 9} ] 解释: const helper = new ImmutableHelper({val: 10}); helper.produce(proxy => { proxy.val += 1; }); // { "val": 11 } helper.produce(proxy => { proxy.val -= 1; }); // { "val": 9 }
示例 2:
输入: obj = {"arr": [1, 2, 3]} mutators = [ proxy => { proxy.arr[0] = 5; proxy.newVal = proxy.arr[0] + proxy.arr[1]; } ] 输出: [ {"arr": [5, 2, 3], "newVal": 7 } ] 解释:对原始数组进行了两次编辑。首先将数组的第一个元素设置为 5。然后添加了一个值为 7 的新键。
示例 3:
输入: obj = {"obj": {"val": {"x": 10, "y": 20}}} mutators = [ proxy => { let data = proxy.obj.val; let temp = data.x; data.x = data.y; data.y = temp; } ] 输出: [ {"obj": {"val": {"x": 20, "y": 10}}} ] 解释:交换了 "x" 和 "y" 的值。
提示:
2 <= JSON.stringify(obj).length <= 4 * 105
produce() 的总调用次数 < 105