JavaScript中调用Array.map后temp变量为何会被同步修改?
问题原因
核心原因是JavaScript的对象引用共享特性,和map方法的返回规则直接相关:
Array.map()确实会返回一个全新的数组,不会修改原数组本身的结构- 但
map不会自动深拷贝数组里的元素:你在回调里直接返回原student对象时,新数组里存的是指向原对象的内存引用,不是对象的独立副本 - 你在回调里写
student.status = 'xxx'的时候,修改的是内存里的原对象本身,所有指向这个对象的引用访问到的都是修改后的值
代码执行流程拆解
- 第一次生成
temp.actions时:
遍历到yearsCompleted === 4的Sarah对象,直接把这个对象的status改为'wow',再把对象引用存入新数组。此时temp.actions[2]和原数组objectsArray[2]指向内存中同一个对象。第一次打印temp时,对象状态是修改后的wow,符合预期。 - 第二次生成
temp2.actions时:
再次遍历到同一个Sarah对象,直接把它的status改为'foo',同样把对象引用存入temp2的新数组。此时内存里的Sarah对象本身已经被修改,不管是temp.actions里存的引用、原数组里的引用、还是temp2.actions里的引用,访问到的都是被改成foo的同一个对象,所以后续打印temp时会看到status被改成了foo。
修复方法
不要在map回调里直接修改原对象,而是返回一个新建的对象副本,切断引用关联:
const objectsArray = [ {'id': 1, 'name': 'Erik', 'yearsCompleted': 2, 'status': 'student'}, {'id': 2, 'name': 'Carol', 'yearsCompleted': 1, 'status': 'student'}, {'id': 3, 'name': 'Sarah', 'yearsCompleted': 4, 'status': 'student'} ]; const temp = { actions: objectsArray.map(student => { // 用展开运算符创建对象副本,仅修改副本属性,不影响原对象 if (student.yearsCompleted === 4) { return {...student, status: 'wow'} } return {...student} }) } const temp2 = { actions: objectsArray.map(student => { if (student.yearsCompleted === 4) { return {...student, status: 'foo'} } return {...student} }) }
修改后temp、temp2、原数组三者的对象完全独立,后续操作不会互相影响。
内容的提问来源于stack exchange,提问作者Michael Gee
相关产品推荐
相关产品推荐

