在开篇之前,先普及一下基本知识。在js中变量类型可以分为两大类,分别是:
- 基本类型:
包括
String,Boolean,Number,null, undefined,symbol。在栈上存储的是这些基本类型确切的值。 - 引用类型:
引用类型大致有
Array与Object两大类(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。莫非引用类型的传递不是按值传递?
实际上,引用类型也是按照值传递,只不过传递的是栈内存的地址的副本,而不是堆内存实际值的副本,在函数内部改变的值是堆内存中的实际值,传递过来的栈内存地址的副本并未改变,要是改变的话,就不可能指向同一个对象了,因此引用类型也是值传递,只不过,传递的是栈上的地址副本,并不是真正的堆内存中的值副本
结论
对于基本类型,按值传递传递的是栈内存上的实际值副本
对于引用类型,按值传递传递的是栈内存上的地址副本,并不是堆内存中的实际值副本