用新值更新不可变的 js 嵌套对象

Posted

技术标签:

【中文标题】用新值更新不可变的 js 嵌套对象【英文标题】:Update immutable js nested object with new value 【发布时间】:2021-09-18 21:16:23 【问题描述】:

我有 2 个不可变对象。结构如下图


    const state = fromJS(
       "a":"value1",
       "b":
          "c":"value2"
       ,
       "d":[ ],
       "e":
          "f":"value3",
          "g":
             "h":true
          
       
    )
    
    and
     
    const updateVal = fromJS(
    "b":"c": "newValue",
       "e": "g":"h": false"
    )

我想要的结果是


     state = fromJS(
       "a":"value1",
       "b":
          "c":"newValue"
       ,
       "d":[ ],
       "e":
          "f":"value3",
          "g":
             "h":false
          
       
    )

我尝试了 mergeWith、mergeDeep 但总是得到结果


    var state = fromJS(
           "a":"value1",
           "b":
              "c":"newValue" // this is updating as I have same new object structure
           ,
           "d":[ ],
           "e": // here I am loosing other values
              "g":
                 "h":false
              
           
        )

所以“e”中的所有内容都将替换为“updateVal”

我尝试过的


    state.mergeWith((prev, next) => 
      if(!prev) return next;
      return next;
    , updateVal)

这只是一个结构,“updateVal”是动态的,我不知道 updateVal 会出现什么。所以如果某些结构匹配然后替换那些特定的值

【问题讨论】:

预期的输出有格式错误,我不确定在哪里。你能不能修一下。另外,请将确切的版本命名为 uf immutable.js。一些合并函数的行为从 3.8.x 到 4.0.x 略有变化 【参考方案1】:

mergemergeWithupdate 都执行 更新,这意味着它们只会将第一级深度的内容复制到另一个对象中。这样一来,一些值可能会丢失,因为整个地图“e”会被新地图“e”替换。

另一方面,mergeDeep 遍历并比较每个级别的集合。它将它们合并,产生您所期望的结果:

(请注意,在 ImmutableJS 版本 3.8.x 和 4.0.x 中合并有一些差异,但在这种情况下它们无关紧要)

const state = Immutable.fromJS(
  "a": "value1",
  "b": 
    "c": "value2"
  ,
  "d": [],
  "e": 
    "f": "value3",
    "g": 
      "donttouchme": "ok",
      "h": true
    
  
);

const updateVal = Immutable.fromJS(
  "b": 
    "c": "newValue"
  ,
  "e": 
    "g": 
      "h": false
    
  
);

const result = state.mergeDeep(updateVal);
console.log(result.toJS());
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.14/immutable.min.js"></script>

【讨论】:

【参考方案2】:

我希望我能正确解释我的方法。您可能可以执行以下操作,获取对象 A 和对象 B,并使用 Proxy object with handler 基于 A 和 B 的超集创建一个新对象 C。

你创建一个函数接受两个对象并返回一个对象。然后遍历第一个对象的键,检查第二个对象是否也具有这些键,并且当您再次遇到对象时,此调用需要递归,但我希望这对您的旅程有所帮助。如果有帮助,我也可以编写一些示例代码来分享。

【讨论】:

只有当对象是 not immutable.js immutables 时,此答案才有效。可以使用toJS 将它们转换回普通对象,然后再次使用fromJS,但对性能不利 抱歉,由于某种原因,我没有看到这与 Immutable.js 对象有关。您仍然可以使用带有处理程序的 Proxy 对象进行合并,但使用 Immutable.js 内部的 mergeDeep() 函数可能会更好。我确实想说,我只是简单地尝试了 Immutable.js,它似乎通过_root.entries 确实是可变的。使用seal 和freeze 可能更容易。

以上是关于用新值更新不可变的 js 嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章

在 React/Redux reducer 中,如何以不可变的方式更新嵌套数组中的字符串?

8.6

在 Immutable.js 中使用 React 的不可变助手

python 递归地将嵌套的dicts转换为嵌套的namedtuples,为您提供类似于不可变对象文字的东西

二Python开发---8浅拷贝与深拷贝

Python坑:不要使用可变对象作为函数默认值生成器不保留迭代过后的结果嵌套列表创建==和is的区