【问题标题】:Dynamically delete object property JavaScript动态删除对象属性 JavaScript
【发布时间】:2020-07-08 17:47:59
【问题描述】:

我有以下代码来获取给定对象的密钥。所以对于对象{"hello": {"data": {"a": "world", "b": "random"}}},如果传入的键是hello.data.a,那么输出就是world。

(object, key) => {
    const keyParts = key.split(".");
    let returnValue = object;
    keyParts.forEach((part) => {
        if (returnValue) {
            returnValue = returnValue[part];
        }
    });
    return returnValue;
}

我试图弄清楚如何以相同的方式动态删除属性。因此,例如对于相同的对象和键,它会将对象更改为 {"hello": {"data": {"b": "random"}}}。

基本上我希望与delete object.hello.data.a 具有相同 的行为。但问题是hello.data.a 部分是传入的动态字符串。当然,delete object[key] 之类的东西不起作用,因为键具有嵌套级别。如果它只有 1 级深,它会起作用,但不适用于嵌套项。

另一个重要的注意事项是,在这种情况下,性能非常重要。因此,尽管创建一个新对象并复制除我要删除的那个之外的所有属性可能 工作,但我非常担心它与 delete 关键字的性能影响。 p>

由于其他外部因素,我也不想将属性值设置为null 或undefined。我希望真正从对象中删除密钥。

我怎样才能做到这一点?

【问题讨论】:

    标签: javascript


    【解决方案1】:

    要删除,.pop() 关闭最后一个键以标识要删除的属性。如果您想避免使用delete 关键字,您还需要替换该键所在的最后一个对象,而不是对其进行变异,因此.pop() 将下一个键关闭为好吧。

    然后,使用您当前的方法(或.reduce)访问最后一个外部对象。删除其中一个键:

    • 要使用delete 进行变异,使用保存的密钥,使用delete[nextLastKey][lastKey]
    • 要创建一个全新的对象但没有保存的键,请在创建新对象期间使用 rest 语法排除 lastKey,然后将新对象分配给父对象的 nextLastKey:

    const fn = (object, key) => {
        const keys = key.split(".");
        const lastKey = keys.pop();
        const nextLastKey = keys.pop();
        const nextLastObj = keys.reduce((a, key) => a[key], object);
        
        // delete version:
        // delete nextLastObj[nextLastKey][lastKey]
        
        // non-delete version:
        const { [lastKey]: _, ...rest } = nextLastObj[nextLastKey];
        nextLastObj[nextLastKey] = rest;
        return object;
    }
    
    const obj = {"hello": {"data": {"a": "world", "b": "random"}}};
    const result = fn(obj, 'hello.data.a');
    console.log(result);

    【讨论】:

    • 这适用于尽可能多的嵌套对象或键的深度,对吗?
    • 是的,密钥可以任意深。不过,它不能任意浅 - 例如{ foo: 'foo' } 不能在不使用delete 的情况下从中删除foo 属性
    • 知道了!为此,我可能只编写条件代码来检查. 是否存在于key 变量中,然后通过执行delete object[key] 正常删除它。
    • 到目前为止,这个解决方案看起来不错,并且通过了我编写的测试。需要更多的定制才能使其与我的用例一起使用,但我认为它会完美运行。如果可能的话,希望对它的工作原理进行更多解释。看起来这是因为 nextLastObj 是引用而不是值的副本,删除它会起作用吗?如果您可以进一步详细说明您的答案,我会很高兴,这样我自己和其他人就可以更多地了解为什么会这样,以及这里的基本概念。非常感谢您的帮助!!
    • 您需要替换最后一个对象以在不使用delete 的情况下从中“删除”一个键。使用 only 最后一个键,您不能替换最后一个对象(出于同样的原因,{ foo: 'foo' } 加上 'foo' 不起作用),但是使用倒数第二个键,您可以替换其父对象上的最后一个对象。通过保存倒数第二个键,您可以在父对象上重新分配。
    【解决方案2】:

    实际上,您的答案就在那里 - 在您提供的代码 sn-p 中。它只需要稍作修改,如下所示:

    const delProp = (object, key) => {
        const keyParts = key.split(".");
        let returnValue = object;
        
        let parent, lastKey;  // added
        keyParts.forEach((part) => {
            if (returnValue) {
                parent = returnValue; // added
                lastKey = part;  // added
                returnValue = parent[lastKey];
            }
        });
        
        if(parent) {
          delete parent[lastKey];  // added
        }
        
        return returnValue;
    }
    
    
    const obj = {"hello": {"data": {"a": "world", "b": "random"}}};
    
    console.log(delProp(obj, 'hello.data.a'));
    console.log(obj)

    还要注意,在 JS 中 for 循环本质上是 more efficient 而不是 forEach 数组函数。因此,我会更改相关部分:

    for (const i = 0, i = keyParts.length; i++) {
        // ...
    }
    

    【讨论】:

      【解决方案3】:

      你可以使用lodash库_.omit函数

      _omit(object, path)

      https://lodash.com/docs/4.17.15#omit

      小心,因为这个函数不会改变对象,而是返回一个没有删除键的新对象。

      【讨论】:

        【解决方案4】:

        您仍然可以使用括号语法删除。

        我添加了另一个示例,因为反对者似乎认为它无法做到。只要您知道基本对象,就应该没有区别。我将通过“。”离开拆分。作为一个简单的练习,因为它不是核心问题的一部分。

        var thing = {"hello": {"data": {"a": "world", "b": "random"}}};
        delete thing.hello.data["a"];
        console.log(thing);
        
        
        var thing2 = {"hello": {"data": {"a": "world", "b": "random"}}};
        delete thing2["hello"]["data"]["a"];
        console.log(thing2);

        【讨论】:

        • 记住,输入字符串是hello.data.a,它是动态的,可以随时改变。
        • 我否决了这个答案,因为正如问题作者所说,属性的路径是动态的,所以标准方式delete thing.hello.data["a"]; 不是解决方案
        • @MarkSchultheiss 我看不出您的回答对这里有什么帮助,即使问题包含您发布的相同代码并说它不起作用,您写道拆分部分不是问题的核心,但确实如此。基本上你把整个答案作为练习!
        猜你喜欢
        • 2020-05-25
        • 2010-09-17
        • 1970-01-01
        • 2021-09-26
        • 1970-01-01
        相关资源
        最近更新 更多