了解 Javascript 中 Find 方法的行为

Understanding Behaviour of Find method in Javascript

let arr = [{ age: 3 }, { age: 5 }, { age: 6 }, { age: 7 }];
let exists = arr.find(x => x.age < 4);
exists.age += 1;
console.log(arr);

//output is [{age:4},{age:5},{age:6},{age:7}];

在上面的例子中,我更新了 find 方法返回的结果,但它也改变了原始数组的值,为什么这样呢?

Array.prototype.find 将 return 满足您作为回调函数传递的条件的第一个元素。

因为您正在寻找 age 属性 小于 4 的对象。所以它将 return 第一个对象(其 age3)。因此,如果您要检查 existsarr[0] 是否相等,那么它将 return 对象满足条件

let arr = [{ age: 3 }, { age: 5 }, { age: 6 }, { age: 7 }];
let exists = arr.find((x) => x.age < 4);

console.log(exists === arr[0])

因此,如果您打算对通过 find 方法 return 编辑的对象进行任何类型的修改,那么原始对象将反映这些更改。

因为两者都是同一个对象,只是引用不同而已。


如果您不想改变原始对象,那么您应该在对该对象进行任何类型的更改之前克隆它。

Note: Both of the following method does shallow copy

1) 使用 spread syntax

let arr = [{ age: 3 }, { age: 5 }, { age: 6 }, { age: 7 }];
let exists = arr.find((x) => x.age < 4);

const clone = { ...exists };
clone.age += 1;
console.log(arr);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

2) 使用 Object.assign

let arr = [{ age: 3 }, { age: 5 }, { age: 6 }, { age: 7 }];
let exists = arr.find((x) => x.age < 4);

const clone = Object.assign({}, exists);
clone.age += 1;
console.log(arr);

因为你有一个对象引用数组。在 JavaScript 中,对象实际上存储在别处(称为“堆”),对象变量实际上仅包含对象的 引用 。所以原因是因为你正在更新同一个对象。

如果你想做一个对象的浅克隆,你可以使用Object.assign({}, obj)

此外,与您的问题没有直接关系,如果您的对象属性 本身 包含其他对象引用,包括数组,并且您希望它们也成为副本,您将不得不深度克隆它们。这不是由股票 JavaScript 函数或方法自动完成的。您必须找到为您执行此操作的代码或自己编写。上次我这样做时,我使用了 randa 的克隆功能,因为我团队中的另一个开发人员已经将 ramda 库导入到我们的项目中。对您的项目最有意义的可能有所不同。

这是因为 JavaScript 中的对象是通过引用传递的,您在存在的对象 ({age : 3} ) 中添加了 1 到它的“年龄”键,因此原始对象也发生了变化。

let obj1 = {age: 3 , name: 'jack' }
let obj2 = obj1

console.log(obj1 === obj2 )  // true

// if you change the second object , the first one will change too :

obj2.age = 15

console.log(obj1 , obj2 )  

// obj1 = { age: 15 , name: 'jack' } 
// obj2 = { age: 15 , name: 'jack' }