Array filter 返回一个新数组,它不会更新原始数组。直接返回或保存到变量中进行更改
const increaseItem = (array = [], dish) => {
return array.filter(//your code here);
//return array;
}
// OR
const increaseItem = (array = [], dish) => {
const newArray = array.filter(//your code here);
return newArray;
}
然而,这并不是你想象的那样。你应该改用map
const increaseItem = (array = [], dish) => {
return array.map((item) => {
if (item.id === dish.id) {
item.quantity++;
}
return item; // Add this
});
}
filter 只会在回调函数返回 true 时从数组中返回值。您的函数没有检查它是否应该过滤,它试图修改值(并且是)。
map 将返回数组每个索引的回调值。因此,如果您在最后返回每个项目,您给定的回调应该会达到您的预期。
最后一个问题是确保你不会改变状态。 这很可能是您的问题的根源。
const increaseItem = (array = [], dish) => {
return array.map((item) => {
let item = {...item}; // Add this
if (item.id === dish.id) {
item.quantity++;
}
return item;
});
}
使用map 和filter,您正在创建一个新的状态数组。 但是,在执行item.quantity++; 时,您正在改变原始状态和新状态的嵌套对象,因为嵌套对象仍在使用相同的引用。在映射时创建一个新对象不仅可以确保主状态数组是新的,而且任何嵌套对象也是如此(这个特定示例仅保护 1 个深度)。
说明
它比答案长,但我想把它说清楚。
您遇到的问题很常见,与 JavaScript 如何处理非原始数据类型有关。当您创建一个数组或对象并将其分配给一个变量时,该变量实际上并不包含该对象,它包含一个引用或指向该对象的指针。对象本身实际上存储在内存中的其他位置。
为了清楚起见,我们只用<> 包围的数字来表示引用。
让我们创建一个对象:
let obj1 = {a: 'b'};
obj1 持有对我们创建的新对象的引用,假设引用是 。现在让我们制作一个对象的副本。
let obj1 = {a: 'b'};
let obj2 = obj1;
console.log(obj1);
console.log(obj2);
由于变量包含一个引用,因此实际分配obj2 的是与 相同的引用。
obj1
// reference: <1>
// value: {a: 'b'}
obj2
// reference: <1>
// value: {a: 'b'}
所以这里出现了误解,因为人们认为obj2 现在是它自己独立的原始副本。但正如您所见,它们引用了内存中的同一个对象。结果是,现在执行obj2.a = 'c' 之类的操作会导致obj1.a 也等于“c”。
运行下面的sn-p自己看看:
let obj1 = {a: 'b'};
let obj2 = obj1;
obj2.a = 'c';
console.log(obj1);
console.log(obj2);
我们如何避免制作误导性副本?
最简单的方法是创建一个全新的对象,然后使用 spread syntax 将旧对象的值填充。
let obj1 = {a: 'b'};
let obj2 = {...obj1};
// obj1
// reference: <1>
// value: {a: 'b'}
// obj2
// reference: <2>
// value: {a: 'b'}
obj2.a = 'c';
console.log(obj1);
console.log(obj2);
现在你可以看到我们复制了一个对象,但是每个对象都引用了自己在内存中的对象。这几乎总是我们想要的行为。
当我们引入嵌套时,事情变得更加混乱。但是,如果您了解基本概念,它应该会更有意义。
let obj1 = {
foo: 'bar',
nested: {a: 'b'}
};
// obj1
// reference: <1>
// value: {foo: 'bar', nested: <2>}
// nested
// reference: <2>
// value: {a: 'b'}
嵌套对象也有自己的引用。因此,当我们解构以创建新对象时,这就是我们正在做的事情。
let obj2 = {...obj1};
obj1
// reference: <1>
// value: {foo: 'bar', nested: <2>}
nested
// reference: <2>
// value: {a: 'b'}
obj2
// reference: <3>
// value: {foo: 'bar', nested: <2>}
obj2 引用了内存中的一个新位置,但嵌套对象的引用仍然和以前一样!
因此,如果我们修改嵌套属性,即使我们在顶部创建了一个新对象,我们也会有与以前类似的行为。这称为“浅拷贝”。试试看:
let obj1 = {
foo: 'bar',
nested: {a: 'b'}
};
let obj2 = {...obj1};
obj2.nested.a = 'c';
console.log(obj1);
console.log(obj2);
解决方案:创建所有嵌套值的新对象。
let obj2 = {...obj1, nested: {...obj1.nested}};
现在我们已经成功创建了一个嵌套对象的完全独立副本。
obj1
// reference: <1>
// value: {foo: 'bar', nested: <2>}
nested
// reference: <2>
// value: {a: 'b'}
obj2
// reference: <3>
// value: {foo: 'bar', nested: <4>}
nested
// reference: <4>
// value: {a: 'b'}
您可以编辑obj2 及其嵌套值,确信obj1 及其嵌套值将保持不变。
let obj1 = {foo: 'bar', nested: {a: 'b'}};
let obj2 = {...obj1, nested: {...obj1.nested}};
obj2.nested.a = 'c';
console.log(obj1);
console.log(obj2);