为何修改数组内对象的check值后,所有前置console.log均显示新值?
为什么修改引用类型后所有前置console.log都显示新值?
我来给你掰扯清楚这个问题——你遇到的其实是JavaScript引用类型的浅拷贝特性,加上浏览器控制台的“懒加载”机制共同导致的坑,咱们一步步拆解:
首先先明确你的示例数据模型:
{ key: '1234', class: 'Math 10', fname: 'john', lname: 'doe', homework: [ {key: '123', check: 'yes'}, {key: '12356', check: 'no'}, {key: '12356789', check: 'na'}, ] }
你尝试用slice()复制数组来规避引用问题,但还是踩了坑,你的调试代码如下:
const value = event.target.getAttribute("data-value"); console.log("data-value is = ", value); const studentKey = event.target.getAttribute("data-studentkey"); console.log("student key is = ", studentKey); const selectedHomeworkKey = this.state.selectedHomework; console.log("Seleted Homework Key is ", selectedHomeworkKey); const students = this.state.students.slice(); console.log("state says students are", students); const selectedStudents = students.filter((student)=>{ return( student.key === studentKey); }) console.log("After filter, students is ", selectedStudents); const nonSelectedStudents = students.filter((student)=>{ return( student.key !== studentKey); }) console.log("Non selected students are ", nonSelectedStudents); const homeworkArray = selectedStudents[0].homework.slice(); console.log("homework of the selected student is ", homeworkArray); const selectedHomework = homeworkArray.filter((homework) => { return (homework.key === selectedHomeworkKey); }) console.log("selected homework for selected student is ", selectedHomework); let updatedHomework = selectedHomework.slice(); console.log("updated homework before update is", updatedHomework) updatedHomework[0].check = value; console.log("updated homework after update is", updatedHomework)
问题根源有两个:
slice()是浅拷贝,没切断对象引用
不管是students.slice()还是homeworkArray.slice(),slice()只能复制数组这个“容器”本身,但数组里的每一个元素——比如你的student对象、homework对象——都是引用类型,它们的内存引用还是和原state里的对象完全一致。所以你看似复制了数组,其实数组里的对象和原数据是同一个,修改updatedHomework[0].check本质上是直接修改了原对象的属性,所有指向这个对象的引用都会同步看到变化。浏览器控制台的“懒求值”特性
你以为console.log是在执行那一刻拍了个数据快照?其实不是!浏览器控制台为了优化性能,对于引用类型(对象、数组),不会立刻把所有值都打印出来,而是当你点击展开这个对象/数组的时候,才会去读取它当前的实时状态。所以哪怕你是先console.log再修改属性,等你后来展开这个log条目时,看到的已经是修改后的新值了。
解决办法:
- 打印时生成快照:如果要看到执行那一刻的真实状态,可以把对象序列化后再打印,生成一个独立的深拷贝快照:
注意:这个方法有局限性,无法处理函数、Symbol等特殊类型,但调试普通对象/数组足够用。console.log("updated homework before update is", JSON.parse(JSON.stringify(updatedHomework))) - 真正的深拷贝:如果需要修改时完全不影响原数据,可以用现代浏览器支持的
structuredClone()方法,或者自己写递归深拷贝函数来彻底切断引用。 - 单独打印原始值:如果只是调试用,也可以直接打印你关心的属性值(比如
check),因为原始值是值传递,不会受后续修改影响:console.log("before check value", updatedHomework[0].check)
内容的提问来源于stack exchange,提问作者Bromox
相关产品推荐
相关产品推荐

