在JavaScript中使用递归更新嵌套的json对象
我正在尝试从现有对象创建更新的对象。 示例对象是:在JavaScript中使用递归更新嵌套的json对象,javascript,arrays,object,recursion,Javascript,Arrays,Object,Recursion,我正在尝试从现有对象创建更新的对象。 示例对象是: // sample object const testObj = { a: 1, b: { c: 2, d: { e: 3, f: { g: 4 } } } }; 我想从上面的对象中创建一个新对象,并将每个值串联起来: // expected object const expectedObject= { a: '1 a', b: { c:
// sample object
const testObj = {
a: 1,
b: {
c: 2,
d: {
e: 3,
f: {
g: 4
}
}
}
};
我想从上面的对象中创建一个新对象,并将每个值串联起来:
// expected object
const expectedObject= {
a: '1 a',
b: {
c: '2 a',
d: {
e: '3 a',
f: {
g: '4 a'
}
}
}
};
以下是我的示例代码:
let expectedObject = {};
const newObject = object => {
Object.entries(object).forEach(([key, value]) => {
if (typeof value === "object") {
Object.keys(value).map(key => {
value[key] = value[key] + " a";
return value;
});
expectedObject[key] = value;
//return newTest;
} else {
expectedObject[key] = value;
return expectedObject;
}
});
return expectedObject;
};
console.log(newObject(testObj));
控制台中的结果是:
{a: 1, b: {…}}
a: 1
b:
c: "2 a"
d: "[object Object] a"
__proto__: Object
__proto__: Object
我想在这里使用递归,也尝试过,但运气不好。
有什么帮助吗,谢谢?您可以获得一个新对象我的映射更改值并创建新对象
功能映射(对象,fn){
返回Object.fromEntries(对象
.条目(对象)
.map([k,v])=>[k,v&&typeof v==='object'?map(v,fn):fn(v)])
);
}
var object={a:1,b:{c:2,d:{e:3,f:{g:4}},
结果=映射(对象,v=>v+'a');
控制台日志(结果)代码>这里有一种方法,使用对原始代码的修改来演示为了使其正常工作需要更改哪些内容。您将一些东西切换到读取值
并设置新值。另外,我正在使用spread操作符在修改对象之前克隆它
const testObj={
答:1,,
b:{
c:2,
d:{
e:3,
f:{
g:4
}
}
}
};
const newObject=object=>{
const clonedObj={…object};
const entries=Object.entries(clonedObj);
entries.forEach(([key,value])=>{
如果(值的类型==“对象”){
clonedObj[key]=newObject(值);
}否则{
clonedObj[key]=值+a;
}
});
返回克隆对象;
};
log(newObject(testObj));
console.log(testObj);//证明原始对象没有改变
,这里有一个简单的递归技术。它与Nina的类似,但它保留了结构中存在的数组
如果输入t
是一个数组,则使用遍历函数f
遍历每个数组值v
,创建一个新数组
(感应)否则t
不是数组。如果t
是一个对象,则使用遍历函数f
遍历每个值v
,从键值对[k,v]
创建一个新对象
(归纳)否则,t
不是数组,t
不是对象。这意味着t
是一个基本值,如字符串、数字或null
下面的编号注释与上面的解释相对应-
const identity=x=>
x
常量遍历=(f=标识,t={})=>
Array.isArray(t)//1
? from(t,v=>遍历(f,v))
:对象(t)==t//2
? Object.fromEntries(Object.entries(t).map([k,v])=>[k,transverse(f,v)])
:f(t)//3
常量输入=
{a:[1,11,111],b:{c:2,d:{e:[3,{f:{g:4}}]}
常量输出=
遍历(x=>`${x}a`,输入)
log(输出)
这只是对@user633183答案的重构。我非常喜欢这种方法,但我认为可以通过提取两个可重用函数来简化它。这开始是对这个答案的评论,但我认为最好是直截了当
const map=(f)=>(a)=>
a、 地图(f)
常量mapObj=(f)=>(o)=>
Object.entries(o).reduce((a[k,v])=>({…a[k]:f(v)}),{})
常数遍历=(f)=>(t)=>
Array.isArray(t)
? 地图(导线测量(f))(t)
:对象(t)==t
? mapObj(导线测量(f))(t)
:f(t)
常量输入=
{a:[1,11,111],b:{c:2,d:{e:[3,{f:{g:4}}]}
常量输出=
遍历(x=>`${x}a`)(输入)
console.log(输出)
下面是一个使用的解决方案。它的工作原理是在遍历输入的同时构建解决方案
//const objectScan=require('object-scan');
常量testObj={a:1,b:{c:2,d:{e:3,f:{g:4}};
const cloneAndModify=(obj)=>objectScan(['**']{
breakFn:({property,value,isLeaf,context})=>{
如果(属性===未定义){
返回;
}
const ref=context[context.length-1];
if(!(ref中的属性)){
ref[property]=isLeaf?`${value}a`:{};
}
push(ref[property]);
},
filterFn:({context})=>{
context.pop();
}
})(obj,[{}])[0];
常数r=cloneAndModify(testObj);
控制台日志(r);
//=>{b:{d:{f:{g:'4A'},e:'3A'},c:'2A'},a:'1A'}
。作为控制台包装{最大高度:100%!重要;顶部:0}
const a=o=>Object.keys(o).reduce((p,c)=>((p[c]=typeof o[c]==“Object”?a(o[c]):o[c]+“a”),p),{})
I jus将您的代码复制到inex.js
文件,并使用node index.js
运行,出现以下错误:TypeError:Object.fromEntries不是函数
NB这将数组[]
转换为对象{}
使用基于字符串的键也值得一提。@Yahya:但是从entries
编写自己的很容易,可以通过折叠结果:(entries)=>entries.reduce((a,[k,v])=>({…a,[k]:v}),{})或使用对象.assign
:(entries)=>Object.assign.apply(null,entries.map([k,v])=>({[k] :v})
。后者更难看,但是。@ScottSauyet非常感谢您的解释。Nina Scholz的答案很好,但我接受另一个答案,因为它符合要求,没有任何错误。建议的重构:拿出一个mapObject
函数用于第2部分。这是一个可重用的函数,使ain代码非常清晰请注意,1
应标记为“归纳型”,而不是3
。谢谢Scott。您的答案很好地分解了这个问题。