在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。您的答案很好地分解了这个问题。