You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何修改数组内对象的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)

问题根源有两个:

  1. slice()是浅拷贝,没切断对象引用
    不管是students.slice()还是homeworkArray.slice(),slice()只能复制数组这个“容器”本身,但数组里的每一个元素——比如你的student对象、homework对象——都是引用类型,它们的内存引用还是和原state里的对象完全一致。所以你看似复制了数组,其实数组里的对象和原数据是同一个,修改updatedHomework[0].check本质上是直接修改了原对象的属性,所有指向这个对象的引用都会同步看到变化。

  2. 浏览器控制台的“懒求值”特性
    你以为console.log是在执行那一刻拍了个数据快照?其实不是!浏览器控制台为了优化性能,对于引用类型(对象、数组),不会立刻把所有值都打印出来,而是当你点击展开这个对象/数组的时候,才会去读取它当前的实时状态。所以哪怕你是先console.log再修改属性,等你后来展开这个log条目时,看到的已经是修改后的新值了。

解决办法:

  • 打印时生成快照:如果要看到执行那一刻的真实状态,可以把对象序列化后再打印,生成一个独立的深拷贝快照:
    console.log("updated homework before update is", JSON.parse(JSON.stringify(updatedHomework)))
    
    注意:这个方法有局限性,无法处理函数、Symbol等特殊类型,但调试普通对象/数组足够用。
  • 真正的深拷贝:如果需要修改时完全不影响原数据,可以用现代浏览器支持的structuredClone()方法,或者自己写递归深拷贝函数来彻底切断引用。
  • 单独打印原始值:如果只是调试用,也可以直接打印你关心的属性值(比如check),因为原始值是值传递,不会受后续修改影响:
    console.log("before check value", updatedHomework[0].check)
    

内容的提问来源于stack exchange,提问作者Bromox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:56:41