JavaScript数组按引用传参可改值但无法重赋值原数组的原因
JavaScript 函数的参数传递规则是按值传递:当传入的参数是引用类型(数组、对象等)时,形参拿到的是「原始引用的地址副本」,既不是原始引用本身,也不是引用指向值的深拷贝。
为什么在函数内修改数组成员,外部数组会同步更新
把外部的myArray传入myFunction时,内部形参arr存储的地址副本,和外部myArray存储的地址指向同一块堆内存,也就是同一个数组实体。
此时调用arr.push(4)是直接修改这块内存里存储的数组内容,没有改动arr本身存储的地址值,所以内外两个引用指向的都是同一个被修改过的数组,外部打印自然能看到变化。
对应示例代码:
let myArray = [1, 2, 3]; console.log( JSON.stringify(myArray) ); // [1, 2, 3] function myFunction(arr) { arr.push(4); console.log( JSON.stringify(arr) ); // [1, 2, 3, 4] return arr; } myFunction(myArray); console.log( JSON.stringify(myArray) ); // [1, 2, 3, 4]
(示例配套样式,不影响逻辑:
.as-console-wrapper {max-height: 100% !important;top: 0;} .as-console-row::after {display: none !important;}
)
为什么在函数内给形参重赋值,不会影响外部数组
在函数内部执行arr = [0]时,本质是修改函数作用域内形参arr这个变量存储的地址值,让它从原来指向[1,2,3]的内存地址,改为指向新创建的[0]数组的内存地址。
这个改动只作用在函数内部的副本变量上,完全不会修改外部作用域中myArray存储的地址值,所以外部的myArray依然指向原来的[1,2,3],值不会发生变化。
对应示例代码:
let myArray = [1, 2, 3]; console.log( JSON.stringify(myArray) ); // [1, 2, 3] function myFunction(arr) { arr = [0]; console.log( JSON.stringify(arr) ); // [0] return arr; } myFunction(myArray); console.log( JSON.stringify(myArray) ); // [1, 2, 3]
(示例配套样式,不影响逻辑:
.as-console-wrapper {max-height: 100% !important;top: 0;} .as-console-row::after {display: none !important;}
)
为什么全局作用域下直接重赋值可以生效
在全局作用域执行myArray = [0]时,操作的就是全局作用域下myArray这个变量本身,直接修改它存储的地址指向,没有经过函数参数传值时的副本拷贝环节,所以可以直接让myArray指向新的数组,重赋值自然生效。
对应示例代码:
let myArray = [1, 2, 3]; myArray = [0]; console.log(myArray); // [0]
通俗理解:把变量比作写着房间号的房卡。传参进函数相当于给内部形参复印了一张印着相同房间号的新房卡:你拿着复印房卡进房间挪动家具(修改数组/对象本身的内容),持有原房卡的人进房间当然能看到家具变了;但如果你直接把复印房卡上的房间号改成另一个新房间的号码,完全不会影响原房卡上写的房间号,持原房卡的人还是会进到原来的房间。而在全局作用域直接给
myArray赋值,相当于直接涂改原房卡上的房间号,当然会生效。
内容的提问来源于stack exchange,提问作者user10869882

