在迭代它们时重命名对象的键是否安全?

时间:2021-01-26 10:49:05

I'm renaming the keys of an object while iterating them:

我在迭代它时重命名对象的键:

Object.keys(object).forEach(function(oldKey) {
    var newKey = someFunc(oldKey);
    if (newKey !== oldKey) {
        object[newKey] = object[oldKey];
        delete object[oldKey];
    }
}

And I would like to know if this method is safe.

我想知道这种方法是否安全。

In other words, can I be sure that my code will never iterate a key which has been renamed in a previous iteration?

换句话说,我可以确定我的代码永远不会迭代在前一次迭代中重命名的密钥吗?

Thank you very much!!!

非常感谢你!!!

3 个解决方案

#1


3  

No, you aren't safe. You're mutating the object live, based on an array that is not live. If you happen to cross a new name with an old (rename a to b, but b already exists and haven't been reached yet) you're going to have a bad time.

不,你不安全。你正在基于一个不活的数组来实时改变对象。如果您碰巧使用旧名称(将名称重命名为b,但b已经存在且尚未到达),则您将遇到一个糟糕的时间。

You will not come across keys you've already seen, but you have no way to know whether the newKey is not already found in the object.

你不会遇到你已经看过的键,但是你无法知道是否在对象中找不到newKey。

There are workarounds, the situation is similar to .splice()ing an array (removing elements) while you iterate it, and the simple workaround is to iterate backwards, so that you always already pass the altered keys. (Or in your case, checking with the in operator)

有一些解决方法,情况类似于.splice()一个数组(删除元素),当你迭代它时,简单的解决方法是向后迭代,以便你总是传递更改的键。 (或者在您的情况下,与in运营商核实)

You're much better, however, creating and returning a new object:

但是,您可以更好地创建并返回一个新对象:

const newObj = Object.keys(object).reduce(function(result, oldKey) {
    var newKey = someFunc(oldKey);
    return { ...result, [newKey]: object[oldKey] };
}, {});

You get a lot of things for free when you treat all of your data structures as immutables (and more specifically, when the keys never change)

当您将所有数据结构视为不可变数据时(更具体地说,当键永远不会更改时),您可以免费获得大量内容

#2


1  

Object.keys, like many other methods, returns an Array that you can iterate over. This Array is not "live" but a snapshot from the time of taking it (e.g. executing Object.keys). So yes, you're save to use it as intended.

与许多其他方法一样,Object.keys返回一个可以迭代的Array。此数组不是“实时”,而是从获取它时的快照(例如,执行Object.keys)。所以,是的,您可以保存以按预期使用它。

There are very little examples of methods that return "live lists" instead of an Array; I guess you're having NodeLists in mind, that you'll get when using document.querySelectorAll. This however not an Array but a NodeList.

返回“实时列表”而不是数组的方法的示例很少;我想你在使用document.querySelectorAll时会遇到NodeLists。然而,这不是数组而是NodeList。

However, there may be one pitfall I can see is: When a generated newKey already exists in the list of oldKeys (not the current one!). So you may or may not (depending on the position in the array) iterate over the already overwritten new key.

但是,我可以看到一个陷阱:当oldKeys列表中已经存在生成的newKey时(不是当前的!)。所以你可能会或可能不会(取决于数组中的位置)迭代已经被覆盖的新密钥。

#3


0  

Here is a solution to change the key without creating a new Object.

这是一个在不创建新对象的情况下更改密钥的解决方案。

for(key in obj){          
    Object.defineProperty(obj, `myNewName`, Object.getOwnPropertyDescriptor(obj, key));
    delete obj[key];
}

#1


3  

No, you aren't safe. You're mutating the object live, based on an array that is not live. If you happen to cross a new name with an old (rename a to b, but b already exists and haven't been reached yet) you're going to have a bad time.

不,你不安全。你正在基于一个不活的数组来实时改变对象。如果您碰巧使用旧名称(将名称重命名为b,但b已经存在且尚未到达),则您将遇到一个糟糕的时间。

You will not come across keys you've already seen, but you have no way to know whether the newKey is not already found in the object.

你不会遇到你已经看过的键,但是你无法知道是否在对象中找不到newKey。

There are workarounds, the situation is similar to .splice()ing an array (removing elements) while you iterate it, and the simple workaround is to iterate backwards, so that you always already pass the altered keys. (Or in your case, checking with the in operator)

有一些解决方法,情况类似于.splice()一个数组(删除元素),当你迭代它时,简单的解决方法是向后迭代,以便你总是传递更改的键。 (或者在您的情况下,与in运营商核实)

You're much better, however, creating and returning a new object:

但是,您可以更好地创建并返回一个新对象:

const newObj = Object.keys(object).reduce(function(result, oldKey) {
    var newKey = someFunc(oldKey);
    return { ...result, [newKey]: object[oldKey] };
}, {});

You get a lot of things for free when you treat all of your data structures as immutables (and more specifically, when the keys never change)

当您将所有数据结构视为不可变数据时(更具体地说,当键永远不会更改时),您可以免费获得大量内容

#2


1  

Object.keys, like many other methods, returns an Array that you can iterate over. This Array is not "live" but a snapshot from the time of taking it (e.g. executing Object.keys). So yes, you're save to use it as intended.

与许多其他方法一样,Object.keys返回一个可以迭代的Array。此数组不是“实时”,而是从获取它时的快照(例如,执行Object.keys)。所以,是的,您可以保存以按预期使用它。

There are very little examples of methods that return "live lists" instead of an Array; I guess you're having NodeLists in mind, that you'll get when using document.querySelectorAll. This however not an Array but a NodeList.

返回“实时列表”而不是数组的方法的示例很少;我想你在使用document.querySelectorAll时会遇到NodeLists。然而,这不是数组而是NodeList。

However, there may be one pitfall I can see is: When a generated newKey already exists in the list of oldKeys (not the current one!). So you may or may not (depending on the position in the array) iterate over the already overwritten new key.

但是,我可以看到一个陷阱:当oldKeys列表中已经存在生成的newKey时(不是当前的!)。所以你可能会或可能不会(取决于数组中的位置)迭代已经被覆盖的新密钥。

#3


0  

Here is a solution to change the key without creating a new Object.

这是一个在不创建新对象的情况下更改密钥的解决方案。

for(key in obj){          
    Object.defineProperty(obj, `myNewName`, Object.getOwnPropertyDescriptor(obj, key));
    delete obj[key];
}