如何向 JavaScript 中嵌套 JSON 结构中的每个对象添加 属性?

How to add a property to every object in a nested JSON structure in JavaScript?

假设我有一个 API 响应,如下所示:

const data = {
  users: [
    { name: "John", teams: [{ name: "Liverpool" }] },
    { name: "Sam", teams: [{ name: "MC" }, { name: "United" }] },
  ],
  photos: [
    { id: "123", types: ["JPG", "PNG"], comments: [{ description: "sample photo" }] },
  ],
};

我想通过将 rid 属性 添加到每个 object.

来转换它
const data = {
  rid: "ABC",
  users: [
    { rid: "ABC", name: "John", teams: [{ rid: "ABC", name: "Liverpool" }] },
    { rid: "ABC", name: "Sam", teams: [{ rid: "ABC", name: "MC" }, { rid: "ABC", name: "United" }] },
  ],
  photos: [
    { rid: "ABC", id: "123", types: ["JPG", "PNG"], comments: [{ rid: "ABC", description: "sample photo" }] },
  ],
};

我该怎么做?我认为其中涉及某种递归,但我无法起草解决方案?

谢谢。

首先,OP 不会改变 JSON 对象。 JSON 是基于字符串的标准化数据交换格式和具有静态方法的 JavaScript 命名空间。

但是 OP 将递归地 traverse/walk a JSON-conform object-type.

因此这样一个函数的实现只需要考虑 object-types 和数组。

在 array-type 的情况下, 递归调用 发生在对象自己的可枚举 keys/propertiesforEach array-item. In case of an object-type all values =40=]会被递归处理。

对于任何 object-type,另外 assignment 提供的自定义对象(一个或多个条目)发生。

下面提供的函数提供了定义最小值的可能性 object-level 从哪里开始应用赋值。

function recursivelyAssignDataToEveryObjectType(type, data, startLevel = 0, level = 0) {
  if (Array.isArray(type)) {
    type
      .forEach(item =>
        recursivelyAssignDataToEveryObjectType(item, data, startLevel, level + 1)
      );
  } else if (type && 'object' === typeof type) {
    Object
      .values(type)
      .forEach(value =>
        recursivelyAssignDataToEveryObjectType(value, data, startLevel, level + 1)
      );
    if (level >= startLevel) {
      Object.assign(type, data);
    }
  }
}

const data = {
  users: [
    { name: "John", teams: [{ name: "Liverpool" }] },
    { name: "Sam", teams: [{ name: "MC" }, { name: "United" }] },
  ],
  photos: [
    { id: "123", types: ["JPG", "PNG"], comments: [{ description: "sample photo" }] },
  ],
};
recursivelyAssignDataToEveryObjectType(data, { rid: "ABC" }, 2);

console.log({ data });
.as-console-wrapper { min-height: 100%!important; top: 0; }

你只需要用递归函数遍历对象即可。

试试下面的代码片段。

const data = {
  users: [
    { name: 'John', teams: [{ name: 'Liverpool' }] },
    { name: 'Sam', teams: [{ name: 'MC' }, { name: 'United' }] },
  ],
  photos: [
    { id: '123', types: ['JPG', 'PNG'], comments: [{ description: 'sample photo' }] },
    { key: null }, // Fixed null values
  ],
}

function addProperty(obj, key, val) {
  if (!obj || typeof obj !== 'object') return
  if (!Array.isArray(obj)) obj[key] = val
  Object.values(obj).forEach((obj) => addProperty(obj, key, val))
}

addProperty(data, 'rid', 'ABC')

console.log(data)

首先,在 Whosebug 中,您应该始终展示自己的作品。即使您无法获得完整的解决方案,也请向我们展示您的尝试并告诉我们似乎哪里出了问题。我不会回答这个问题,除非这里已经有其他两个合理的答案。


我非常反感修改输入数据,所以我写了一个版本,创建了一个副本,其中 属性 包含在所有 Object 节点上。它看起来像这样:

const addProp = (name, val) => (o) =>
  Array .isArray (o)
    ? o .map (addProp (name, val))
  : Object (o) === o
    ? Object .fromEntries ([
        [name, val], 
        ...Object .entries (o) .map (([k, v]) => [k, addProp (name, val) (v)])
      ])
  : o

const data = {users: [{name: "John", teams: [{name: "Liverpool"}]}, {name: "Sam", teams: [{name: "MC"}, {name: "United"}]},], photos: [{id: "123", types: ["JPG", "PNG"], comments: [{description: "sample photo"}]}]}

console .log (addProp ('rid', 'ABC') (data))
.as-console-wrapper {max-height: 100% !important; top: 0}

我们根据输入是 ArrayObject 还是其他内容,以三种方式进行处理。如果两者都不是,我们 return 值保持不变。如果它是一个数组,我们将递归调用映射到其值上的同一函数。对于一个对象,我们将它分成 name-value 对,通过递归调用映射值并为我们的新 属性 添加一个,然后我们将这些 name-value 条目折叠回一个对象。