【问题标题】:Javascript: Change the value of an element in an array without mutating the arrayJavascript:在不改变数组的情况下更改数组中元素的值
【发布时间】:2018-03-22 04:33:29
【问题描述】:

假设我有一个表单中的数组:

const array = [{id: 1, title: "this"}, {id: 2, title: "that"}];

我想更改给定对象中一个元素的值。因此,例如,我的输出是这样的:

[{id: 1, title: "this"}, {id: 2, title: "foo foo foo"}];

我将一个具有两个属性的对象传递给我的函数。第一个属性是我要修改的对象的id,第二个属性是新标题

[2, "foo foo foo"]

我可以使用以下代码找到正确对象的索引:

index = array.findIndex(item => item.id === arr[0]);

但我不知道如何更改元素并将其替换为我的新标题 (arr[1])。

我想更改第二个对象中的标题元素而不改变数组。非常感谢任何建议。

编辑:对于“不改变数组”的混淆感到抱歉。我的意思是我不希望返回的数组只是原始数组的突变,而是一个新数组。也许“不改变状态”会是一个更好的词选择。

例如,如果我要像这样返回一个数组: 返回 [...状态] 这将给我一个新数组(尽管没有更改),而不会改变原始数组。

【问题讨论】:

  • 发布你的功能
  • 您的要求并不完全清楚。你不能用array.find(({id}) => id === arr[0]).title = arr[1]之类的东西吗?从技术上讲,这不会改变数组,因为它与同一组对象引用仍然相同,但我不确定这是否是您的意思。
  • arr[index].title = "your new value" 不工作吗?
  • 能否请您详细说明“不改变数组”的确切含义
  • @Phil:刚刚编辑了我的问题

标签: javascript arrays element immutability


【解决方案1】:

如果没有……变异它,你就不能真正改变一个对象。您需要该对象的副本。假设复制数组不会花费太多,您可以执行以下操作:

const arr = [{id: 1, title: "this"}, {id: 2, title: "that"}];
const a2 = arr.map(i => i.id == 2 ? Object.assign({}, i, {title: 'foo foo foo'}): i)

console.log("original: ", arr)
console.log("with changes: ", a2)

在这种情况下,您正在复制原始对象,但更改后的对象除外,它会获取更改后的副本并保留原始对象。

【讨论】:

  • 太好了,这行得通。我需要一个新数组的原因是因为这是一个 Redux reducer,如果我没记错的话,不鼓励改变原始数组。
【解决方案2】:

您可以使用Array.map 函数来遍历数组并返回新数组。在map函数中,检查id是否与id passed in the arguments of the function相同。如果条件为真,则使用...(spread operators) 创建一个新对象。

const arr = [{id: 1, title: "this"}, {id: 2, title: "that"}];

var change = (id, title) => {
  return arr.map(obj => {
    if (obj.id === id) {
      return {...obj, title};
    }
    return obj;
  });
}

var arr2 = change(2, "foo foo foo");

console.log("original: ", arr);
console.log("with changes: ", arr2);

【讨论】:

  • 请注意,Safari 仍然不支持对象扩展 ({...object})。当我运行 sn-p 时,这对我来说会抛出错误。
  • 是的,这似乎还没有在 Safari 中实现(仅在 chrome 和 firefox 中)。感谢您指出这一点。
  • 太好了,感谢您的解决方案。不过我想我会选择 Mark_M 的解决方案,因为它使用 ES6,而且看起来更简单一些。
【解决方案3】:

const array = [{
    id: 1,
    title: "this"
}, {
    id: 2,
    title: "that"
}];

function replaceTitle(oldArray, [itemId, newTitle]) {
    let newArray = JSON.parse(JSON.stringify(oldArray));
    (newArray.find(({id}) => id === itemId) || {}).title = newTitle;
    return newArray;
}

const newArray = replaceTitle(array, [2, 'foo foo foo']);
console.log('ORIGINAL', array);
console.log('UPDATED', newArray);

【讨论】:

  • 这不正是 OP 说他们不想做的吗? array 已更改。
【解决方案4】:

你没有改变数组。您正在更改数组中包含的对象的属性。该数组存储对您的对象的引用。

如果您想更改数组中的对象但仍想保留原始对象,则必须对存储在数组中的所有对象进行深度复制。

【讨论】:

  • 如果只更改一个对象,为什么还需要深度复制数组中的所有个对象?
  • 对,您不需要深度复制所有对象,只需对正在更改的对象进行深度复制。这样也更有效率。除非您打算随意修改其他对象,否则您需要深度复制所有内容,否则您最终会修改原始数组值。
  • 数组是 Redux 状态的一部分,我认为我必须返回一个全新的数组(而不是仅仅深度复制和更改一个对象),否则我将改变状态。对吗?
猜你喜欢
  • 2021-04-14
  • 2019-08-13
  • 2012-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 2019-10-26
  • 2020-09-13
相关资源
最近更新 更多