JS深入之参数传递方式

132 阅读2分钟

在开篇之前,先普及一下基本知识。在js中变量类型可以分为两大类,分别是:

  1. 基本类型: 包括String,Boolean,Number,null, undefined,symbol。在栈上存储的是这些基本类型确切的值。
  2. 引用类型: 引用类型大致有ArrayObject两大类(Date, Reg等只是Object的特殊变形),在栈上存储的是引用类型的地址,真正的实际值是存在于堆上的。

按值传递

按值传递是指将外部的值,拷贝一份,作为函数的实参。函数内部对实参的改变是不会改变外部的值。听起来有点绕,看个简单的例子吧

var value = '外部的value'
function test(param) {
  param = '我改变了value的值'
  console.log(param)
}
test(value) // 我改变了value的值
console.log(value) // 外部的value

在以上的代码中,我们将变量value的值作为参数,在函数内部更改了参数的字符串,之后再打印之前的变量value,value的值还是没传递之前的,这也就证明了是将外部变量拷贝了一个副本,函数内部改变此副本并不会影响外面。

但是,请看下面这个例子:


var obj = {
  name: 'Bye丶L',
  age: 23
}
function changeUserAge(user) {
  user.age = 24
  console.log(user)
}
changeUserAge(obj) // {name: "Bye丶L", age: 24}
console.log(obj) // {name: "Bye丶L", age: 24}

这就奇了怪了,不说说好的值传递不会更改传入的参数吗,这个怎么改变了obj中的age。莫非引用类型的传递不是按值传递?
实际上,引用类型也是按照值传递,只不过传递的是栈内存的地址的副本,而不是堆内存实际值的副本,在函数内部改变的值是堆内存中的实际值,传递过来的栈内存地址的副本并未改变,要是改变的话,就不可能指向同一个对象了,因此引用类型也是值传递,只不过,传递的是栈上的地址副本,并不是真正的堆内存中的值副本

结论

对于基本类型,按值传递传递的是栈内存上的实际值副本
对于引用类型,按值传递传递的是栈内存上的地址副本,并不是堆内存中的实际值副本