1. 基础数据类型
函数参数中,如果是基础数据类型,肯定是按值传递,这个应该没有太多疑问,例如:
js
const a = 1
test(a)
function test(params) {
console.log(params)
}
我们会理解为:
params赋值了a的值,即params = 1。
所以基础数据类型,函数参数是按值传递,没问题
2. 引用数据类型
引用数据类型,也是按值传递。
js
const obj = { a: 1 }
changeObj(obj)
console.log(obj) // { a: 2 }
function changeObj(params) {
params.a = 2
params = { b: 2 }
}
以上代码中
changeObj函数里的
params.a = 2
确实有效的更改了obj的值
可以得出结论:函数传参中,如果是引用数据类型,能够修改到引用类型里的属性。但这不意味着函数传参中是按引用传递的。后续的
params = { b: 2 }
并不影响obj的值
可以得出结论:函数传参中,如果是引用数据类型,也是按值传递的。
要解释上面这两个结论,先从js代码执行入手,js代码执行会为程序分配三部分内存:代码、栈、堆,这些统称为地址空间。
- 引用数据类型会在栈中存放地址,该地址指向堆。
- 例子里的obj便是在堆中,栈里0x0001只存放了指向该堆的地址,我们称其为地址A。
- 在函数传递时,只是在栈中新建一个内存空间0x0002,且将其赋值地址A,只赋值了地址。
- 因为只存了地址值,所以便能解释结论2【函数传参中,如果是引用数据类型,也是按值传递的】。
- 因为地址值指向原本的堆,所以结论1也就解释通了【函数传参中,如果是引用数据类型,能够修改到引用类型里的属性】
- params = { b: 2 } 也仅仅只是将新的内存空间0x0002里的地址A擦除,赋值了新的堆地址,对原栈中的0x0001没有影响。
总结
想要更深入了解,可以参考 https://developer.51cto.com/article/595152.html