数组赋值是地址拷贝,非值拷贝也非引用传递;复制的是堆中数组的内存地址,故改元素同步、换数组不同步、传参实为传地址副本。

数组在 JavaScript 中不是“值类型”,也不是传统意义的“引用传递”,而是地址拷贝——赋值时复制的是堆内存中数组对象的地址,不是数据本身,也不是直接共享变量名。这个细节决定了所有后续行为:改元素会同步,换数组不会同步,传参看似“引用”实则“传地址副本”。
数组赋值 = 地址拷贝,不是值拷贝
当你写 let arr1 = [1, 2, 3]; let arr2 = arr1;,JavaScript 并没有复制三个数字,也没有创建新数组,只是把 arr1 指向的那块堆内存的地址,原样给了 arr2。它们就像同一扇门的两把钥匙。
-
arr2[0] = 99→arr1[0]也变成 99(访问同一内存位置) -
arr2 = [4, 5, 6]→arr1仍为[99, 2, 3](arr2现在指向新地址,与arr1断开) -
arr2.push(7)→arr1.length也会变(操作的是同一数组实例)
函数参数传递:统一按值,但“值”的含义不同
JS 所有函数参数都是按值传递。对数组来说,“值”就是那个地址——所以形参拿到的是地址的副本,不是原始地址本身,但副本和原地址指向同一块堆内存。
- 若函数内写
param[0] = 'x',外部原数组会变(改的是共享堆内存) - 若函数内写
param = ['new'],外部不变(只是让形参指向新地址,不影响实参) - 判断关键:看赋值左边是不是变量名本身。是
param = …→ 不影响外层;是param[i] = …或param.push()→ 可能影响外层
浅拷贝 ≠ 创建独立数组,只是第一层“断链”
浅拷贝方法(如 slice()、[...arr]、Array.from(arr))会新建一个数组容器,但只复制顶层元素的值——对普通数字/字符串没问题,对嵌套对象或数组,仍拷贝的是地址。
-
let a = [1, {x: 2}]; let b = [...a]; b[0] = 99;→a[0]不变(数字是原始类型) -
b[1].x = 99;→a[1].x也变成 99(对象仍是同一地址) - 真正隔离需深拷贝:
structuredClone(a)或JSON.parse(JSON.stringify(a))(注意限制)
原始类型数组?不存在的
数组永远是引用类型,哪怕它只装数字。你不能靠“里面全是原始值”就认为它可被值拷贝。它的身份由构造方式决定:[]、Array()、new Array() 创建的都是对象,存于堆,栈里只存地址。
- 对比:
let n = 42; let m = n;——m是n的独立副本,改m绝不影响n - 而:
let a = [42]; let b = a;——a和b共享底层存储,改b[0]就是改a[0] - 根本差异不在内容,而在存储位置与赋值机制:栈值 vs 堆址 + 栈指针

















