如何递归替换对象中的密钥名称



我正试图弄清楚如何使用递归将对象的键名替换为新的键名(这也包括嵌套对象内部的键名(。我觉得这与我在第一个if条件语句中重新分配给newObj的方式有关。有什么建议吗?这是我到目前为止的代码:

// 24. Find all keys in an object (and nested objects) by a provided name and rename
// them to a provided new name while preserving the value stored at that key.
const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
for(let key in obj){
if (key === oldKey){
newObj[newKey] = obj[key]    
} 
if (typeof obj[key] === 'object'){
replaceKeysInObj(obj[key], oldKey, newKey);
}
else {
newObj[oldKey] = obj[key]
}
}
return newObj
}

var obj = {'e':{'e':'y'},'l': 'l','y':'e'};
console.log(replaceKeysInObj(obj, 'e', 'new')) 

对方法进行一些修改

const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
if (typeof obj !== "object") return obj; 
for (let key in obj) {
newObj[key === oldKey ? newKey : key] = replaceKeysInObj(obj[key], oldKey, newKey);
}
return newObj;
};
const obj = { e: { e: "y" }, l: "l", y: "e" };
console.log(replaceKeysInObj(obj, "e", "new"));
const obj2 = { e: { e: "y" }, l: { e: "y" }, y: "e" };
console.log(replaceKeysInObj(obj2, "e", "new"));

试试这个函数:

function replaceKeysInObj(obj, oldKey, newKey) {
Object.keys(obj).map((key) => {
if(typeof obj[key] === 'object') {
replaceKeysInObj(obj[key], oldKey, newKey);
}
if(key === oldKey) {
obj[newKey] = obj[oldKey]
delete obj[oldKey];
}
});
return obj;
}
let obj = {'e':{'e':'y'},'l': 'l','y':'e'};
console.log(replaceKeysInObj(obj, 'e', 'new'))

如果我们更普遍地考虑这个问题,我们可以编写一个简单的递归。我们可以编写一个函数,用对当前键调用函数的结果替换任意嵌套对象中的所有键。我们可以通过各种方式使用它。如果我们想将所有键转换为大写,我们会将其传递给k => k.toUpperCase()。或者,对于您的情况,我们可以编写类似k => k == oldKey ? newKey : k的内容。这个想法的一个实现可能是这样的:

const replaceKey = (f) => (o) =>
Array .isArray (o) 
? o .map (replaceKey (f))
: Object (o) === o
? Object .fromEntries (Object .entries (o) .map (([k, v]) => [f(k), replaceKey (f) (v)]))
: o
const replaceKeysInObj = (oldKey, newKey) =>
replaceKey (k => k == oldKey ? newKey : k)
const testCase = {foo: 1, bar: {baz: 2, qux: {corge: [{baz: 3}, {baz: 4}]}}}
console.log (
replaceKey (k => k.toUpperCase()) (testCase)
) //~> {FOO: 1, BAR: {BAZ: 2, QUX: {CORGE: [{BAZ: 3}, {BAZ: 4}]}}}
console.log (
replaceKeysInObj ('baz', 'grault') (testCase)
) //~> {foo: 1, bar: {grault: 2, qux: {corge: [{grault: 3}, {grault: 4}]}}}
.as-console-wrapper {max-height: 100% !important; top: 0}

请注意,我对您的函数的API做了一些更改。如果你想要原始签名,我们可以写

const replaceKeysInObj = (obj, oldKey, newKey) =>
replaceKey (k => k == oldKey ? newKey : k) (obj)

但我写它的方式有一个优势,我经常利用这个优势。它使我们可以部分地应用oldKeynewKey来获得可重用的函数

const e2new = replaceKeysInObj ('e', 'new')
// later
e2new ({e: {e: 'y'}, l: 'l', y: 'e'}) //=> {new: {new: "y"}, l: "l", y:"e"}

但这里有一点值得注意:通常更简单的做法是从我们当前的问题中抽象出至少一点,编写一个更通用的解决方案,配置一两个函数来填充细节。即使我们最终放弃了抽象并内联这些配置函数,它也可以帮助我们更清楚地看到问题。

如果要更改对象键名称我认为这是有效的!

if (oldKey !== newKey) {
Object.defineProperty(obj, newKey, Object.getOwnPropertyDescriptor(obj, oldKey));
delete o[oldKey];
}

根据您发布的代码,如果您希望返回一个带有替换键的新对象,而不是更改对象,请将其更改为以下内容:

const replaceKeysInObj = (obj, oldKey, newKey, newObj = {}) => {
for (let key in obj) {
if (key === oldKey) {
newObj[newKey] = obj[key];
} else {
newObj[key] = obj[key];
}
if (typeof obj[key] === 'object') {
newObj[newKey] = replaceKeysInObj(obj[key], oldKey, newKey);
}
}
return newObj;
};
var obj = {
'e': {
'e': 'y',
},
'l': 'l',
'y': 'e',
};
console.log(replaceKeysInObj(obj, 'e', 'new'));
// { new: { new: 'y' }, l: 'l', y: 'e' }

根据@Scott Sauyet的回答,我做了一个函数。您可以在CodeSandbox上看到示例CodeSandbox链接

export const replaceKeysInObj = (data, oldKey, newKey) => {
const replaceKey = (f) => (newdata) => {
if (Array.isArray(newdata)) return newdata.map(replaceKey(f));
if (Object(newdata) === newdata) {
return Object.fromEntries(
Object.entries(newdata).map(([key, value]) => [
f(key),
replaceKey(f)(value)
])
);
}
return data;
};
return replaceKey((key) => (key === oldKey ? newKey : key))(data);
};

最新更新