【问题标题】:Delete an object from a nested array of objects从嵌套的对象数组中删除一个对象
【发布时间】:2019-04-30 20:02:41
【问题描述】:

我有这个小函数(在我的 Angular 7 应用程序中),它使用 JavaScript reduce(),并在嵌套的对象数组中定位一个对象。然后我可以继续即时更新某些属性。

现在,除了这个查找逻辑之外,我还想将一个对象 insert/delete 放入/取出嵌套数组。

问题是:一旦我找到我的对象,我可以 push() 和/或删除一个对象吗?

const input={UID:2,GUID:"",LocationName:"USA",ParentLocation:null,subs:[{UID:42,GUID:"",LocationName:"New Jersey",Description:"",subs:[{UID:3,GUID:"",LocationName:"Essex County",ParentLocation:null,"subs":[{UID:4,LocationName:"Newark",ParentLocation:3,"subs":[{"UID":49,"GUID":"","LocationName":"Doctor Smith's Office","LocationType":{"UID":2,"LocationTypeName":"Practice","Description":"other location"},"subs":[{"HostID":38,"HostName":"Ocean Host",}]}]}]}]}]};

const findUIDObj = (uid, parent) => {
  const { UID, subs } = parent;
  if (UID === uid) {
    const { subs, ...rest } = parent;
    return rest;
  }
  if (subs) return subs.reduce((found, child) => found || findUIDObj(uid, child), null);
};
console.log(findUIDObj(49, input));

var obj = findUIDObj(49, input);
delete obj; 

例如,在我的 Angular 7 应用程序中,如果我尝试 delete 找到的对象,它会报错:

前/

var obj = findUIDObj(49, input);
delete obj; 

  'delete' cannot be called on an identifier in strict mode.

【问题讨论】:

  • 据我了解,您无法在严格模式下删除嵌套对象。您必须创建一个过滤掉指定对象的新对象。
  • delete 也不适用于数组...它会留下孔并且不会改变长度。使用splice() 从数组中删除对象,因此您需要确定数组中的索引
  • 另外,如果要“删除”的对象是根对象,那应该怎么办?为了更加一致,您的 input 对象应该是一个类似于 subs 数组的数组。
  • 我不会使用delete 运算符。我会简单地返回对象的副本,而不包含您不需要的东西。
  • 在严格模式下,您可以使用 delete 从对象中删除属性。

标签: javascript angular typescript multidimensional-array angular7


【解决方案1】:

简要查看您的代码,我发现您正在使用const 标识符来声明您的数据收集。我们只将const 用于不会改变的静态数据,这就是它的目的。所以,首先,这似乎是问题所在。要对其进行测试,请将其更改为 let。现在,对于数据管理的方法,不变性值得您考虑,原因有很多,但即 Angular 将重新渲染整个对象,而不管更改现有对象或接收新对象。您可以查看 Immutable JavaScript 以了解更多信息。在许多情况下,创建不可变数据管理是通过库完成的,您可以自己完成。基本上,创建一个名为copy( data ) 的函数,或者其他东西,这样您就可以传入原始对象,但您会得到它的副本作为回报,而不引用原始对象。这样就不会意外更改原始对象。为此,您可以在复制功能中执行此操作:return JSON.parse(JSON.stringify( data )) ;

您在这里可能遇到的唯一问题是深层嵌套对象,或者具有循环引用的对象可能会导致问题。我有一个覆盖stringify 的方法来管理我编写的小库中的这个。

【讨论】:

    【解决方案2】:

    delete obj 永远不会做你想做的事:首先,它甚至不是你输入的对象,因为函数从找到的对象创建了一个 new 对象,不包括@987654322 @ 属性,并返回。但更重要的是,delete 用于删除属性,而不是对象。

    您似乎想从其父 subs 属性中删除匹配的对象。为此,您需要改变 subs 数组,因此它会排除匹配的对象。为了以通用方式工作,您的输入应该是一个数组。否则无法从任何东西中删除根对象。

    考虑到这一点,您的查找函数应该返回在其中找到匹配项以及在哪个索引处的数组。通过这些信息,您可以决定从数组中删除该元素,或者在该索引处插入另一个对象。

    这是它如何与删除一起工作:

    const input=[{UID:2,GUID:"",LocationName:"USA",ParentLocation:null,subs:[{UID:42,GUID:"",LocationName:"New Jersey",Description:"",subs:[{UID:3,GUID:"",LocationName:"Essex County",ParentLocation:null,"subs":[{UID:4,LocationName:"Newark",ParentLocation:3,"subs":[{"UID":49,"GUID":"","LocationName":"Doctor Smith's Office","LocationType":{"UID":2,"LocationTypeName":"Practice","Description":"other location"},"subs":[{"HostID":38,"HostName":"Ocean Host",}]}]}]}]}]}];
    
    const findUIDObj = (uid, arr) => {
        if (!arr) return;
        const idx = arr.findIndex(obj => obj.UID === uid);
        if (idx > -1) return [arr, idx];
        for (const obj of arr) {
            const result = findUIDObj(uid, obj.subs);
            if (result) return result;
        }
    };
    console.log(findUIDObj(49, input));
    
    const [arr, idx] = findUIDObj(49, input) || [];
    if (arr) {
        arr.splice(idx, 1); // Remove object from its parent array
    }

    【讨论】:

    • 正确。我尝试使用delete 命令删除对象的错误(我应该知道得更好)。顺便说一句,在这种情况下,我只能删除一个叶节点;在我更新这个嵌套树之前,会发生一个单独的操作。
    • 直到今天,我才在我的应用程序中正确测试过您的想法。效果很好,谢谢。我上面的原始帖子可以让我简单地找到一个对象并更新它,你更新的逻辑允许我迭代每个子数组并找到所需的索引 - arr.findIndex() - 然后通过 splice() 方法删除它。
    猜你喜欢
    • 2021-12-28
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2019-11-02
    • 2021-10-29
    • 1970-01-01
    相关资源
    最近更新 更多