Javascript 更改名称匹配的深嵌套数据结构中的属性

Javascript 更改名称匹配的深嵌套数据结构中的属性,javascript,Javascript,我有这样一些数据结构: { "category": "Fruits", "department": "ABC123", "content": { "subcategory1": [ { "fruitName": "Apples", "inStock": false }, { "fruitName": "Pears", "inStock": false } ]

我有这样一些数据结构:

{
  "category": "Fruits",
  "department": "ABC123",
  "content": {
    "subcategory1": [
      {
        "fruitName": "Apples",
        "inStock": false
      },
      {
        "fruitName": "Pears",
        "inStock": false
      }
    ],
    "subcategory2": [
      {
        "fruitName": "Oranges",
        "inStock": false
      },
      {
        "fruitName": "Lemons",
        "inStock": false
      }
    ]
  }
}
我希望能够根据一些输入更新“inStock”值。我有这样一个数组:

[“梨”、“橙”]

对于该数组中属性的所有实例,我希望将
inStock
更新为
true
以结束:

{
  "category": "Fruits",
  "department": "ABC123",
  "content": {
    "subcategory1": [
      {
        "fruitName": "Apples",
        "inStock": false
      },
      {
        "fruitName": "Pears",
        "inStock": true
      }
    ],
    "subcategory2": [
      {
        "fruitName": "Oranges",
        "inStock": true
      },
      {
        "fruitName": "Lemons",
        "inStock": false
      }
    ]
  }
}

我想为此编写一些通用函数,这样我就可以执行类似于
constnewdata=updateStock(oldData)的操作。然而,我不知道如何开始写这篇文章。如果我能得到一些关于开始的建议(即使不是解决方案),我将非常感谢。

请始终在OP中发布您的尝试,以便我们了解您是如何接近的

您可以使用
Array.filter
Array.forEach

let数据={
“类别”:“水果”,
“部门”:“ABC123”,
“内容”:{
“子类别1”:[
{
“水果名”:“苹果”,
“inStock”:错误
},
{
“水果名”:“梨”,
“inStock”:错误
}
],
“子类别2”:[
{
“水果名”:“橙子”,
“inStock”:错误
},
{
“水果名”:“柠檬”,
“inStock”:错误
}
]
}
}
函数updateStock(名称){
Object.values(data.content.flat())
.filter(d=>names.includes(d.groutname))
.forEach(d=>d.inStock=true)
}
updateStock(['Oranges','Pears']))

console.log(data)
我在看到@NitishNarang的答案之前就开始写这篇文章了,所以我将完成并对其进行一点扩展

从把你的问题分解成更小的部分开始

首先,您需要一种方法来更新对象的
inStock
属性。稍后我们将继续更新嵌套数据结构中的多个对象

这里我将采用函数方法。让我们编写一个高阶函数(可以说是“工厂”函数)。当使用属性名和值调用时,它将返回一个新函数。当使用对象调用此新函数时,将使用设置为指定值的属性更新该对象:

const updateProperty = (key, value) => obj => {
  obj[key] = value;
  return obj;
};
请注意,此函数可用于各种情况。如果需要,我们可以创建一个函数,用值
chocolate
更新名为
material
的键:

const renderUseless = updateProperty('material', 'chocolate');
例如:

const teapot = { material: 'china' };
renderUseless(teapot);
无论如何,我们可以使用
updateProperty
来做更多有用的事情,比如创建方便的函数,将商品标记为库存或缺货:

const setInStock = updateProperty('inStock', true);
const setOutOfStock = updateProperty('inStock', false);
现在,我们如何将一堆东西标记为库存

const products = [
  {
    fruitName: 'Apples',
    inStock: false
  },
  {
    fruitName: 'Pears',
    inStock: true
  }
];

products.forEach(setInStock);
那么,我们如何只为那些匹配给定谓词的元素运行函数呢?我们可以使用
Array.filter
,当给定一个数组时,它将返回一个新数组,其中只包含通过给定谓词的那些项

让我们构建一个接受水果名称数组的函数,如果其输入对象具有包含在该数组中的
水果名称
属性,则返回返回
true
的谓词,否则返回
false

const hasFruitName = names => item =>
  names.includes(item.fruitName);
与数组一起使用。过滤器

const products = [
  {
    fruitName: 'Apples',
    inStock: false
  },
  {
    fruitName: 'Pears',
    inStock: true
  }
];

const matchingProducts = products.filter(isFruitName(['Apples']));
现在我们有了一个平面数组的解决方案。我们只需要处理嵌套的数据结构。如果您有一个包含多个数组的嵌套对象,我们如何创建一个项目的平面数组

Object.values(data.content)
将从对象
data.content
中获取值,生成数组数组。要将其扁平化为单个数组,我们可以使用
array.flat
,但它还没有得到广泛支持。让我们制作一个等效的便携功能:

const flattenNestedArray = arr => [].concat.apply([], arr);
const getItemsFromData = data =>
  flattenNestedArray(Object.values(data.content));
现在让我们制作另一个方便的函数:

const flattenNestedArray = arr => [].concat.apply([], arr);
const getItemsFromData = data =>
  flattenNestedArray(Object.values(data.content));
综合起来,我们得到:

const setFruitInStock = (fruitNames, data) =>
  getItemsFromData(data)
    .filter(hasFruitName(fruitNames))
    .forEach(setInStock);
这有点过度设计,但希望它能说明从小型、通用、高阶函数开始的好处。你最终会得到很多小的、可重复使用的助手,这些助手会成长为稍微更专业的构建块。每件事都有明确的名称,当您到达最终实现时,一目了然发生了什么

最后,我添加了
数据
作为第二个参数,因此您的函数更易于重用


我将把重构这个问题留给纯粹性(即不改变输入数据)作为OP的练习:)

发布的问题似乎根本不包括解决问题的方法。StackOverflow希望您能这样做,因为您的尝试有助于我们更好地了解您的需求。请编辑问题以显示您已尝试的内容,以便说明您遇到的具体障碍。有关更多信息,请参阅并将。如果您认为答案有帮助,则向上投票和/或接受答案被认为是礼貌的。@NitishNarang和我都花了时间和精力帮助你。很好。解释了拼图的每一部分。