代码之家  ›  专栏  ›  技术社区  ›  Thidasa Pankaja

是否可以使用lodash更新嵌套对象的特定值?

  •  1
  • Thidasa Pankaja  · 技术社区  · 2 年前

    我有一个像这样的嵌套对象

    let obj = {
      id: "XXX",
      children: [
        {
          id: "YYY",
          children: [],
          path: ["XXX", "YYY"],
          type: "text"
        },
        {
          id: "ZZZ",
          children: [],
          path: ["XXX", "ZZZ"],
          type: "button"
        }
      ],
      path: ["XXX"],
      type: "row"
    };
    

    我需要循环浏览所有 儿童 并更新 路径 通过附加一个字符串数组 const newPath = ["A", "B", "C"];

    let newObj = cloneDeepWith(obj, (node) => {
      if (node.id) {
        node = { ...node, path: [...newPath, ...node.path] };
        console.log("updated : ", node)
      }
    });
    

    所以更新对象的最终输出应该是

    let obj = {
      id: "XXX",
      children: [
        {
          id: "YYY",
          children: [],
          path: ["A", "B", "C", "XXX", "YYY"],
          type: "text"
        },
        {
          id: "ZZZ",
          children: [],
          path: ["A", "B", "C", "XXX", "ZZZ"],
          type: "button"
        }
      ],
      path: ["A", "B", "C", "XXX"],
      type: "row"
    };
    

    我正试图用lodash中的cloneDeepWith函数这样做

    let updatedObj = cloneDeepWith(obj, (node) => {
      if (node.id) {
        node = { ...node, path: [...newPath, ...node.path] };
        console.log("updated : ", node)
      }
    });
    

    在每个console.log中,它都会打印更正后的更新节点(在本例中为3,带有父节点),但不会返回 updatedObj

    我怎样才能做到这一点?

    2 回复  |  直到 2 年前
        1
  •  1
  •   Keith    2 年前

    我不知道该怎么做 lodash ,但使用纯JS做这件事相当容易。你的 recursion 标签是关键。。

    如。

    let obj = {
      id: "XXX",
      children: [
        {
          id: "YYY",
          children: [],
          path: ["XXX", "YYY"],
          type: "text"
        },
        {
          id: "ZZZ",
          children: [],
          path: ["XXX", "ZZZ"],
          type: "button"
        }
      ],
      path: ["XXX"],
      type: "row"
    };
    
    function addABC(obj) {
      if (obj.path) obj.path = ['A','B','C',...obj.path];
      if (obj.children) for (const s of obj.children) addABC(s);
    }
    
    addABC(obj);
    
    console.log(obj);
        2
  •  0
  •   Nenad Vracar    2 年前

    您可以使用Lodash来完成此操作 cloneDeepWith 方法,但在这种情况下,它也会修改原始数据。

    let obj = {
      id: "XXX",
      children: [{
          id: "YYY",
          children: [],
          path: ["XXX", "YYY"],
          type: "text"
        },
        {
          id: "ZZZ",
          children: [],
          path: ["XXX", "ZZZ"],
          type: "button"
        }
      ],
      path: ["XXX"],
      type: "row"
    };
    
    const newPath = ["A", "B", "C"];
    
    const clone = _.cloneDeepWith(obj, value => {
      if (_.isArray(value.path)) {
        value.path = [...newPath, ...value.path]
      }
    })
    
    console.log(clone)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
        3
  •  0
  •   Scott Sauyet    2 年前

    没有库的不可变方法可能是这样的:

    const prependPaths = (prefix) => ({path, children, ...rest}) => ({
      ...rest,
      path: [...prefix, ...path],
      children: children .map (prependPaths (prefix))
    })
    
    const obj = {id: "XXX", children: [{id: "YYY", children: [], path: ["XXX", "YYY"], type: "text"}, {id: "ZZZ", children: [], path: ["XXX", "ZZZ"], type: "button"}], path: ["XXX"], type: "row"}
    
    console .log (prependPaths (['A', 'B', 'C']) (obj))
    .as-console-wrapper {max-height: 100% !important; top: 0}

    这是一个简单的递归,其中我们 map 使用我们的函数,通过预配置 prefix 参数(此处, ['A', 'B', 'C'] .)

    但请注意,您的物品 path 节点携带一些冗余信息,这些信息可以从id的层次结构中派生,如果您有一个不包含这些信息的原始表单 路径 节点,您仍然可以通过大约相同的努力实现相同的效果:

    const addPaths = (prefix = []) => ({id, children, ...rest}) => ({
      id,
      ...rest,
      path: [...prefix, id],
      children: children .map (addPaths ([...prefix, id]))
    })
    
    // No `path` nodes here.
    const obj2 = {id: "XXX", children: [{id: "YYY", children: [], type: "text"}, {id: "ZZZ", children: [], type: "button"}], type: "row"}
    
    // But the output includes the correct full paths.
    console .log (addPaths (['A', 'B', 'C']) (obj2))
    .作为控制台包装{最大高度:100%!重要;顶部:0}

    主要区别在于递归调用采用前缀的更新版本,添加 id 当前对象的。