前言:js中的数值的类型分为基本类型和引用类型,基本类型有Undefined、Null、Boolean、Number 和 String,而引用类型就是Object。按这个道理,函数传参的时候,应该也会有两种方式,但是函数的参数却只有按值传递。就是只有基本类型给变量赋值一样的传参。究竟是怎么回事呢?
关于js的函数传参,很多人遇到过将对象作为参数传入的场景,并且根据不同的值来设置这个对象参数的不同属性,同时不能影响到外面的对象的属性。遇到这个场景,一般会经历三个步骤:
1.刚接触js时:咋回事?我只改了里面的值,为什么外面的也变了?
2.不管三七二十一,对于传进来的对象参数,先进行如下转化:
let obj1 = JSON.parse(JSON.stringify(obj));
// do something
3.为啥要对传进来的对象进行转化?函数参数不都是按值传递的吗?
不知道大家学习js的有没有经历过类似的这种历程,如果一开始就到第三步的,估计就是一方大佬,请收下我的膝盖。
为了搞清楚第3步,我重新看了红宝书相关的内容,看完之后似懂非懂,再找些大佬的分享,嗯,感觉差不多了。在这里,就跟大家分享一下我自己的感悟,虽然比不上知名大佬的分析,但是还是希望可以给还在第二阶段,想要进入第三阶段的朋友一点感想,也希望各位大佬指出不当之处。
不是引用传递的引用传递
看下面的代码:
function setName(obj){
obj.name = 'Tom';
}
let person = new Object();
setName(person);
console.log(person); // {name: Tom}
没错,这就是上面的第一个步骤,为啥我改了函数里面的参数,外面的也变了?不是说好的没有按引用值传参吗?
先不用急,再看一段代码:
function setName(obj){
obj.name = 'Tom';
obj = new Object();
obj.name = 'Jerry';
}
let person = new Object();
setName(person);
console.log(person); // {name: Tom}
这是红宝书里用来验证对象参数是非引用传递的代码,但是我个人觉得这个代码并不能很好的证明对象参数就不是按引用传递,因为,你把里面的代码放到外面,结果也是一样的:
let person = new Object();
person.name = 'Tom';
person1 = person;
person1 = new Object();
person1.name = 'Jerry';
console.log(person); // {name: Tom}
这个结果和上面的是一样的,难道这也可以验证对象不是按引用传递?
栈区和堆区
我们都知道,js中存储空间分为栈区和堆区,基本数据类型的存储在栈区,而引用数据类型的地址(指针)存储在栈区,而属性集合存储在堆区,如下图所示:


将栈区中的地址值复制一份传递到函数里,这部分地址值和基本类型的传值是一样的,我个人理解,因为这部分都是在栈区进行操作,所以,就归类为按值传递。
这便是我对函数参数只有按值传递的理解了,给我大佬有不同意见,欢迎到本小白github指正!