我有一些类似的数据结构:
{
"category": "Fruits",
"department": "ABC123",
"content": {
"subcategory1": [
{
"fruitName": "Apples",
"inStock": false
},
{
"fruitName": "Pears",
"inStock": false
}
],
"subcategory2": [
{
"fruitName": "Oranges",
"inStock": false
},
{
"fruitName": "Lemons",
"inStock": false
}
]
}
}
我希望能够基于一些输入来更新“ inStock”值。我有一个像这样的数组:
["Pears", "Oranges"]
对于该数组中属性的所有实例,我想将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
}
]
}
}
我想为此编写一些通用函数,以便可以执行类似const newData = updateStock( oldData );
的操作。但是我不确定如何开始写这篇文章。如果我能获得一些入门的指导(即使不是解决方案),我也将非常感激。
答案 0 :(得分:1)
请始终在OP中发布您的尝试,以便我们了解您的处理方式。
您可以尝试使用Array.filter
和Array.forEach
let data = {
"category": "Fruits",
"department": "ABC123",
"content": {
"subcategory1": [
{
"fruitName": "Apples",
"inStock": false
},
{
"fruitName": "Pears",
"inStock": false
}
],
"subcategory2": [
{
"fruitName": "Oranges",
"inStock": false
},
{
"fruitName": "Lemons",
"inStock": false
}
]
}
}
function updateStock(names) {
Object.values(data.content).flat()
.filter(d => names.includes(d.fruitName))
.forEach(d => d.inStock = true)
}
updateStock(['Oranges', 'Pears'])
console.log(data)
答案 1 :(得分:0)
在我看到@NitishNarang的答案之前,我开始写这篇文章,所以我将对其进行扩展和扩展。
首先将您的问题分解成小块。
首先,您想要一种更新对象上的inStock
属性的方法。稍后,我们将继续更新嵌套数据结构中的多个对象。
我将在这里采用一种实用的方法。让我们写一个高阶函数(可以说是“工厂”函数)。当使用属性名称和值调用时,它将返回一个新函数。当使用对象调用此新功能时,该函数将使用设置为指定值的属性来更新该对象:
const updateProperty = (key, value) => obj => {
obj[key] = value;
return obj;
};
请注意,此功能可用于所有方式。如果需要,我们可以创建一个函数,以将material
的键更新为值chocolate
:
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
属性,则返回一个谓词,该谓词返回fruitName
,并且返回{{1} }否则:
false
与const hasFruitName = names => item =>
names.includes(item.fruitName);
结合使用:
Array.filter
因此,我们现在有一个解决方案,用于处理一系列商品。我们只需要处理您的嵌套数据结构。假设您有一个包含多个数组的嵌套对象,那么我们如何创建一个平面的项目数组?
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 setFruitInStock = (fruitNames, data) =>
getItemsFromData(data)
.filter(hasFruitName(fruitNames))
.forEach(setInStock);
作为第二个参数,因此您的函数更具可重用性。
我将保留纯净度(即不改变输入数据)作为OP的练习:)