引用类型的数组:存储的是对象本身还是对象引用?
数组存储的是对象的引用而非对象本身。数组变量在栈中保存堆内存地址,引用类型元素存放内存地址,基本类型元素直接存值。浅拷贝共享引用,深拷贝才独立。函数参数或状态管理中操作引用类型需留意共享问题。
很多初学者刚接触数组时,容易产生一个直觉误区:以为数组里存的就是对象本身。那到底存的是什么呢?一句话说清楚——数组存的是对象的引用,而不是对象自身的全部数据。
为什么?因为数组本身就是引用类型。它的变量在栈内存里只保存一个地址,这个地址指向堆内存中的一段空间。数组里的每个元素,如果本身是引用类型(对象、函数、嵌套数组等),那它存放的不过是指向那个对象的内存地址,而不是把整个对象拷贝到数组的格子里面。
举个例子:let arr = [{name: 'Alice'}, [1,2]]。这里的 arr[0] 存的并不是 {name: 'Alice'} 这个对象的所有属性,而是这个对象在堆里的买入地址;arr[1] 同理,存的是子数组 [1,2] 的地址。所以当你修改 arr[0].name = 'Bob',原对象就直接变了;但假如你用 arr[0] = {} 重新赋值,那只是让索引 0 指向一个新对象,原来的对象纹丝不动。
那基本类型元素呢?比如 let nums = [1, 2, 3],数字 1、2、3 本身是值类型,所以它们的值直接存在数组对应的槽位里。但这并不改变数组整体是引用类型的本质——数组变量 nums 存的是堆内存的地址。你写 let a = nums,a 和 nums 指向同一块堆内存,之后无论是 push 还是 pop,改的都是那块内存里的结构,两个变量都能看到变化。
理解了这个前提,浅拷贝和深拷贝的区别就一清二楚了。浅拷贝(像 slice()、[...arr]、Array.from(arr))只复制外层数组和里面的基本值,对于对象或数组元素,拷贝的仍然是地址——也就是“引用共享”。比如:
let a = [{x: 1}];
let b = [...a];
b[0].x = 99;
console.log(a[0].x); // 输出 99
要想彻底隔离,就必须深拷贝。现代浏览器可以用 structuredClone(a),也可以借助 JSON.parse(JSON.stringify(a))(但只适用于纯数据),或者自己写递归实现。
回到日常编码,有一个常见的坑要留意:别默认“赋值就是复制”。只要涉及对象、数组、函数作为元素,就得意识到——你操作的很可能是共享引用,不是独立副本。
- 函数参数传入数组或对象,内部修改属性会影响外部;但重新赋值(如
arr = [])不会。 - 在状态管理(比如 React 的 state)中更新嵌套对象时,经常需要展开、重建结构来避免意外突变。
- 调试时可以用
Object.is(a, b)判断是否是同一引用,或者用console.log(Object.getPrototypeOf(arr))确认它是 Array 实例。
总之,记住数组存的是引用,而不是对象本体——这句话能帮你避开一大半与此相关的 bug。

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















