Immutable JS深度合并异常:对象被完全覆盖而非部分合并
解决Immutable JS 3.8.1深度合并大型Map时的嵌套属性覆盖问题
我之前碰到过一模一样的坑,这其实是你创建Immutable结构的方式不对导致的——当你用Immutable.Map()把普通对象转成Map时,嵌套的子对象并没有被转换成Immutable Map,还是原生的JS对象。而Immutable 3.8.1的mergeDeep对非Immutable的嵌套值会直接替换,根本不会去深度合并里面的属性。
问题根源拆解
你看这段代码:
const map2 = Immutable.Map(obj2);
这里map2里的"foo.bar"对应的是一个普通JS对象,不是Immutable Map。当你用mergeDeep合并map1时,map1里同键对应的普通对象会直接覆盖掉map2里的值,自然就丢失了key1、key2这些属性。
正确解决方案
要让mergeDeep按预期合并嵌套属性,你需要把整个对象递归转换成Immutable结构,用Immutable.fromJS()代替Immutable.Map()就好:
const obj1 = { "foo.bar": { valid: ['baz'] } } const obj2 = { "foo.bar": { key1: 'abc', key2: [1, 2, 3], valid: ['baz', 'bar', 'foo'] } } // 用fromJS递归转成Immutable嵌套结构 const immutableObj2 = Immutable.fromJS(obj2); const immutableObj1 = Immutable.fromJS(obj1); const mergedResult = immutableObj2.mergeDeep(immutableObj1); console.log(mergedResult.toJS());
运行后就能得到你想要的结果:
{ "foo.bar": { key1: 'abc', key2: [1, 2, 3], valid: ['baz'] } }
原理说明
Immutable.fromJS()会递归处理整个对象:把普通JS对象转成Immutable Map,数组转成Immutable List。这样mergeDeep处理这些嵌套的Immutable结构时,会逐层递归合并属性:
- 顶层的
"foo.bar"键会触发嵌套Map的合并 - 嵌套Map里的
valid(已转成Immutable List)会被合并替换,而key1、key2这类未被覆盖的属性会完整保留
备选方案(手动转换嵌套对象)
如果你因为某些限制不能用fromJS,也可以手动把嵌套的子对象转成Immutable Map,适合结构简单的场景:
const map2 = Immutable.Map({ "foo.bar": Immutable.Map(obj2["foo.bar"]) }); const map1 = Immutable.Map({ "foo.bar": Immutable.Map(obj1["foo.bar"]) }); const mergedResult = map2.mergeDeep(map1); console.log(mergedResult.toJS());
内容的提问来源于stack exchange,提问作者Vinod Kolla
相关产品推荐
相关产品推荐

