如何使用 JavaScript spread... 语法更改对象的一个字段,该字段属于数组并通过名称-值对访问?
Posted
技术标签:
【中文标题】如何使用 JavaScript spread... 语法更改对象的一个字段,该字段属于数组并通过名称-值对访问?【英文标题】:How to use JavaScript spread... syntax to change the one field of the object, that belongs to the array and is accessed by name-value pair? 【发布时间】:2021-01-16 23:22:12 【问题描述】:这是代码(在构建 state2 的句子,即在第二次传播时编译失败):
let line_id = 6;
let state =
invoice:
id: 1015,
description: 'web order',
,
lines: [
id: 5, description: 'phone', color: 'black',
id: 6, description: 'tablet', color: 'blue',
id: 7, description: 'computer', color: 'gray',
]
;
//this alert and this access pattern works, so, I would like to use
//.find... to access element in spread... structure as well
//alert(state['lines'].find(line=>line['id']==line_id)['description']);
let state2 =
...state,
['lines']: ...state['lines'],
find(line=>line['id']==line_id): ...state['lines'].find(line=>line['id']==line_id),
['description']: 'TV',
,
,
;
alert(state2['lines'].find(line=>line['id']==line_id)['description']);
我有state
结构,我访问lines
数组,我通过名称-值对id=6
访问特定行,我想更改字段description
的值。这项工作是https://***.com/a/64116308/1375882 的延续,我在其中尝试创建通用过程,该过程使用 spread... 语法和按名称访问策略来更新复杂的对象/数组树。事实上 - 这个复杂的树是 Redux reducer 的状态,并且更新发生在处理 AgGrid 的 valueSetter
函数的操作中。但是 - 这通常是一个有趣的练习,它本身可以更好地理解传播......以及 javascript 中的 JavaScript 和 JSON 结构。
所以 - 唯一的问题是:如何写行
find(line=>line['id']==line_id): ...state['lines'].find(line=>line['id']==line_id),
这样代码可以编译吗?如何在此设置中通过名称-值对访问数组的特定元素:
请注意,我正在尝试构建通用代码:
find(line=>line[keyFieldName]==keyFieldValue): ...state['lines'].find(line=>line[keyFieldName]==keyFieldValue),
使用任意字段名称和字段值 - 以便此类处理程序可以更新 React/Redux 设置中任意 2D AgGrid 的任意记录的任意字段。
我的代码的预期结果:1)它应该编译; 2) 第二个警报应该返回“TV”。
【问题讨论】:
['lines']:
真的吗?
是的,真的——我打算在这个地方使用字符串类型的变量来通过名称访问对象属性(state.property)。所以 - 现在是 ['lines'],但将来会是 [gridRecords]。
请从给定的数据集中添加想要的结果。
我的代码的期望结果:1)它应该编译; 2)第二个警报应该返回“电视”。
【参考方案1】:
您可以使用数组中的map 方法返回基于原始元素的不同元素。
你可以这样使用它:
line_id = 6;
state =
invoice:
id: 1015,
description: 'web order',
,
lines: [
id: 5, description: 'phone', color: 'black',
id: 6, description: 'tablet', color: 'blue',
id: 7, description: 'computer', color: 'gray',
]
;
state2 =
...state,
lines: state.lines.map(line =>
if (line.id === line_id)
return ...line, description: 'YT'
return ...line
)
;
alert(state2['lines'].find(line=>line['id']==line_id)['description']);
【讨论】:
这不是“想要”或“不要”的问题; state 不应该发生突变,因此我认为您应该删除行line.description = 'TV'
并仅保留当前注释的行 (line = ...line, description: 'TV'
)。 ;)
我同意@secan,更新了它。 state2.invoice
仍然指向原始发票对象,因此在 state2 中更新它也会在 state 中更新它。您可以使用库进行深度克隆或手动进行
@a-a 我没有关注你; state2.invoice
不引用 state.invoice
的同一实体,因为 ...state
创建了 state
的克隆,而不是对同一对象的引用。如果代码是state2 = invoice: state.invoice
,那您是对的,但事实并非如此。我错过了什么吗?
扩展运算符只生成浅拷贝,不生成深层克隆。如果对象有嵌套对象,它不会克隆其中的所有内容,它只是指向它。比如在上面的代码之后你可以执行state2.invoice.id = 12345; console.log(state.invoice.id)
,它会显示原来的状态已经更新了
@TomR, map()
不会修改原始数组,因此您在突变方面应该是安全的。 @a-a,是的,你是对的,我没有考虑过;非常感谢您的回答。 :)【参考方案2】:
如果我正确理解了你想要达到的目标,这应该可行:
let line_id = 6;
let state =
invoice:
id: 1015,
description: 'web order',
,
lines: [
id: 5,
description: 'phone',
color: 'black'
,
id: 6,
description: 'tablet',
color: 'blue'
,
id: 7,
description: 'computer',
color: 'gray'
,
]
;
const stateKeyId = 'lines';
const itemKeyId = 'id';
const itemAttr = 'description'
let state2 =
...state,
[stateKeyId]: state[stateKeyId].map(item =>
if (item[itemKeyId] == line_id)
return (
...item,
[itemAttr]: 'TV'
);
return item
)
console.log(state2);
【讨论】:
【参考方案3】:find(line=>line['id']==line_id)
应该变成[find(line=>line['id']==line_id)]
,因为就像字符串一样,它必须在方括号之间才能让 js 正常工作。
另外,如果您使用来自lodash
的find
,它将返回对象,因此如果您需要使用 id 作为键,您可以执行以下操作:
[get(find(line => line['id'] === line_id]), 'id')]: whatever
不过有一些观察:
请始终在 js 中使用 === 而不是 == 避免snake_case,在js中使用camelCase,因为它是标准的 您的代码实际上并未正确处理丢失的项目,如果您需要这样做,请将其拆分为多行,因为这样更易于理解【讨论】:
以上是关于如何使用 JavaScript spread... 语法更改对象的一个字段,该字段属于数组并通过名称-值对访问?的主要内容,如果未能解决你的问题,请参考以下文章
javascript 使用Spread Operator复制数组
javascript 使用Object spread向对象添加新属性