如何使用 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 正常工作。

另外,如果您使用来自lodashfind,它将返回对象,因此如果您需要使用 id 作为键,您可以执行以下操作:

[get(find(line => line['id'] === line_id]), 'id')]: whatever

不过有一些观察:

请始终在 js 中使用 === 而不是 == 避免snake_case,在js中使用camelCase,因为它是标准的 您的代码实际上并未正确处理丢失的项目,如果您需要这样做,请将其拆分为多行,因为这样更易于理解

【讨论】:

以上是关于如何使用 JavaScript spread... 语法更改对象的一个​​字段,该字段属于数组并通过名称-值对访问?的主要内容,如果未能解决你的问题,请参考以下文章

javascript 使用Spread Operator复制数组

javascript 使用Object spread向对象添加新属性

javascript 使用spread运算符复制对象或数组

javascript 使用Spread运算符来就地评估阵列

在Javascript中是否有python 2.7x中的Object spread语法?

javascript JavaScript Spread运算符