Skip to content
On this page

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 }
}

以上代码中

  1. changeObj函数里的params.a = 2确实有效的更改了obj的值
    可以得出结论:函数传参中,如果是引用数据类型,能够修改到引用类型里的属性。但这不意味着函数传参中是按引用传递的。

  2. 后续的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

课后疑问

参考资料