JS foreach遍历修改对象的问题

发布于 2025-02-08 12:07:32 字数 706 浏览 1 评论 0 原文

为什么第一个修改起作用(当我重新调整对象的属性时)而不是第二个(当我重新分配整个对象时)?

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item = {id:6,value:6}  // modify fail
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }

Why does the first modification work (when I reassign properties of the object) but not the second (when I reassign the whole object)?

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item = {id:6,value:6}  // modify fail
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

牵强ㄟ 2025-02-15 12:07:32

考虑以下示例:

我们创建一个对象并将其分配给变量 foo ,然后我们将 foo 分配给 bar 。因此,现在 foo bar 请参阅以下图所示的同一对象。

let foo = { id: 1, val: "foo" };
let bar = foo;

接下来,让我们更改分配给 bar 的对象的 val 字段。我们注意到更改反映了变量 foo bar ,这是因为两个变量都涉及同一对象。

let foo = {id: 1,val: "foo"};
let bar = foo;
bar.val = "bar";
console.log(foo, bar);

接下来,我们将一个新对象分配给 bar 。请注意,这不会影响 foo 引用的对象, bar 现在只是指另一个对象。

let foo = { id: 1, val: "foo" };
let bar = foo;
bar = { id: 1, val: "bar" };
console.log(foo, bar);

让我们将其与您的问题中的示例相关联。因此,在 foreach 循环的每次迭代中, item 在回调函数中的参数从数组中指向对象,当您从此 item更改字段时参数它更改数组中的对象,但是当您将 item 分配给新对象时,它对存储在数组中的对象没有任何作用。

如果您想用新对象替换整个对象,则可以采用几种方法,其中两种如下:

  1. 找到对象存储的索引并用新对象替换。
const arr = [{ id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 }, { id: 4, value: 4 }, { id: 5, value: 5 }];

const index = arr.findIndex((obj) => obj.id === 3);
if (index !== -1) {
  arr[index] = { id: 6, value: 6 };
}

console.log(arr);

  1. 另一个真正常见的方法是在数组上 MAP ,并创建一个更换该对象的新数组。
const arr = [{ id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 }, { id: 4, value: 4 }, { id: 5, value: 5 }];

const newArr = arr.map((obj) => (obj.id === 3 ? { id: 6, value: 6 } : obj));

console.log(newArr);

Consider the example below:

We create an object and assign it to variable foo and then we assign foo to bar. So, now both foo and bar refer to the same object, as illustrated in the diagram below.

let foo = { id: 1, val: "foo" };
let bar = foo;

enter image description here

Next let's change the val field of the object i.e. assigned to bar. We notice that the change is reflected by both the variables foo and bar and this is because both the variables refer to the same object.

let foo = {id: 1,val: "foo"};
let bar = foo;
bar.val = "bar";
console.log(foo, bar);

enter image description here

Next we assign a new object to bar. Notice this doesn't effect the object that foo refers to, bar is simply now referring to a different object.

let foo = { id: 1, val: "foo" };
let bar = foo;
bar = { id: 1, val: "bar" };
console.log(foo, bar);

enter image description here

Let's relate this to the forEach example in your question. So, in every iteration of the forEach loop, the item argument in the callback function points to an object from the array and when you change a field from this item argument it changes the object in the array but when you assign item to a new object it does nothing to the object stored in the array.

If you want to replace the entire object with a new one, there are several approaches you could take, two of which are mentioned below:

  1. Finding the index where the object is stored and replacing it with a new object.

const arr = [{ id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 }, { id: 4, value: 4 }, { id: 5, value: 5 }];

const index = arr.findIndex((obj) => obj.id === 3);
if (index !== -1) {
  arr[index] = { id: 6, value: 6 };
}

console.log(arr);

  1. Another really common approach is to map over the array and create a new array with that one object replaced.

const arr = [{ id: 1, value: 1 }, { id: 2, value: 2 }, { id: 3, value: 3 }, { id: 4, value: 4 }, { id: 5, value: 5 }];

const newArr = arr.map((obj) => (obj.id === 3 ? { id: 6, value: 6 } : obj));

console.log(newArr);

拥有 2025-02-15 12:07:32

您的混乱是自然的,这与实际对象和变量之间的区别有关。

在您的foreach函数中,您有一个变量“项目”,该变量指向您要循环的数组中的对象。但是,当您运行时,

item = {id:6,value:6}

您不是在修改对象,而是将变量“项目”指向您刚刚创建的新对象。

如果要更改实际对象本身,则可以通过一个一个一个一个一个一个一个地修改值或使用object.sign从另一个对象复制的值来手动执行此操作。

在此片段中,我做了一些示例,希望可以说明差异,最后您使用对象解决了特定案例。分配()

const a = { id: 1, value: 1 };
let b = a; // b now points to the same object as variable a

b = {id: 2, value: 2};

console.log('a', a, 'b', b) // output shows two different objects with different values

const c = {id: 3, value: 3};
const d = c;
Object.assign(c, {id: 4, value: 4});
console.log('c', c, 'd', d); // c and d both have id: 4 and value: 4 because they both point to the same object

const e = { id: 5, value: 5 };
const f = e;
e.id = 6;

console.log('e', e, 'f', f); // directly assigning the value also works


const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
})

arr1.forEach((item, index) => {
    if (item.id === 1) {
        Object.assign(item, {id:6,value:6})  // success with assign
    }
})

console.log(arr1)

Your confusion is natural, and it's to do with the difference between the actual object, and the variable.

In your foreach function, you have a variable "item" which points to the object in the array you are looping. But when you run

item = {id:6,value:6}

You are not modifying the object, but rather making the variable "item" point to a new object that you've just created.

If you want to change the actual object itself, you can do it manually by modifying the values one by one, or by copying from another object using Object.assign.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

In this snippet, I've made a few examples that hopefully illustrate the differences, and at the end your specific case being solved using Object.assign()

const a = { id: 1, value: 1 };
let b = a; // b now points to the same object as variable a

b = {id: 2, value: 2};

console.log('a', a, 'b', b) // output shows two different objects with different values

const c = {id: 3, value: 3};
const d = c;
Object.assign(c, {id: 4, value: 4});
console.log('c', c, 'd', d); // c and d both have id: 4 and value: 4 because they both point to the same object

const e = { id: 5, value: 5 };
const f = e;
e.id = 6;

console.log('e', e, 'f', f); // directly assigning the value also works


const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
]

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
})

arr1.forEach((item, index) => {
    if (item.id === 1) {
        Object.assign(item, {id:6,value:6})  // success with assign
    }
})

console.log(arr1)

酒与心事 2025-02-15 12:07:32

因为 item 是对当前正在迭代的对象的引用,因此修改参考将依次修改原始对象(因此在第一个代码示例中观察到的行为)。在第二个中,您只需重新分配对全新对象的引用,因此您无法再修改您要迭代的原始对象。

基本上,当您用 foreach 循环循环时, item 是一个变量,其当前值是指向当前迭代的对象的引用/指针。修改此对象会修改原始对象(因为它只是一个参考,而不是实际的克隆对象)。但是,当您重新分配它时,该引用不再存在,因为 item 具有指向的新值。您可以像这样修改它,成功:

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
];

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.id = 6;
        item.value = 6;
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }

您也可以通过循环浏览要重新分配的每个属性,也可以动态地做到这一点:

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
];

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        let toConvert = { id: 6, value: 6};
        Object.entries(toConvert).forEach(([k, v]) => item[k] = v);
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }

Because item is a reference to the object that's currently being iterated over, modifying the reference will in turn modify the original object (hence the behaviour observed in your first code example). In the second forEach you just reassign the reference to a brand new object so you can no longer modify the original object you were iterating over.

Basically, when you loop over the array with forEach, item is a variable whose current value is a reference/pointer to the object currently being iterated over. Modifying this object modifies the original (as it's just a reference, not an actual cloned object). However, when you reassign it, the reference is no longer present because item has a new value that it points to. You could modify it like so, with success:

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
];

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.id = 6;
        item.value = 6;
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }

You could do it dynamically as well, by looping over each property you wish to reassign like so:

const arr1 = [
    { id: 1, value: 1 },
    { id: 2, value: 2 },
    { id: 3, value: 3 },
    { id: 4, value: 4 },
    { id: 5, value: 5 },
];

arr1.forEach((item, index) => {
    if (item.id === 1) {
        item.value *= 10   // modify success
    }
});

console.log(arr1);

arr1.forEach((item, index) => {
    if (item.id === 1) {
        let toConvert = { id: 6, value: 6};
        Object.entries(toConvert).forEach(([k, v]) => item[k] = v);
    }
});

console.log(arr1);
.as-console-wrapper { max-height: 100% !important; top: auto; }

一片旧的回忆 2025-02-15 12:07:32

对于第一种情况,可以理解为:

const it = { value: 10 };
const item = it;
item.value = 11;
console.log(it);   // item and it point to the same object, so the object's property value is modified

第二种情况:

const it = { value: 10 };
let item = it;           // Here item and it refer to the same object
item = { value: 6 };     // But here item points to the new object (direct assignment), and it still points to the original object
console.log(item, it);   // So it is still { value: 10 }, and item is already { value: 6 }

For the first case, it can be understood as:

const it = { value: 10 };
const item = it;
item.value = 11;
console.log(it);   // item and it point to the same object, so the object's property value is modified

second case:

const it = { value: 10 };
let item = it;           // Here item and it refer to the same object
item = { value: 6 };     // But here item points to the new object (direct assignment), and it still points to the original object
console.log(item, it);   // So it is still { value: 10 }, and item is already { value: 6 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文