先上代码
let asd = 10
let res = function(num) {
num = 30
return num
}
在上述函数中,声明了一个number类型的变量 asd 同时声明了一个函数,函数接收一个num参数,并且函数体里,将num重新赋值为30,最后返回num。
接下来调用一下这个函数,猜猜会输出啥
console.log(res(asd), asd)
res(asd) //30
asd //10
明明我们已经将asd作为实参传入函数了,按理来说函数内的num=30 也就相当于是asd = 30 那为什么asd却还是10呢
首先要明白,函数的参数传递是按值传递的。我们在传参的时候,传过去的是asd的值。而不是asd这个变量。
函数在接收参数的时候其实就相当于是在做一个copy数据。 形参 = 实参 。将实参赋值给形参。 在本例子中其实就可以看成是一个基本类型的数据在做赋值一样。
而基本类型的数据赋值,是会重新开辟一个内存来存储copy出来的那份数据的。并且copy出来的数据和原数据是互不干扰的
也就是说此时内存中其实存了两个 10 分别是asd 和num。 当我们在函数体内修改num的时候,也就是去修改num的内存里的值。这自然就不会影响到asd了。 所以上述代码输出的就是 30 和10
再来看一个例子
let ao = {
name:123
}
function fs(obj){
obj.name = 456
}
fs(ao)
console.log(ao)
console.log(ao) //{name: 456}
上述同样是赋值,但是却成功的影响到了实参。这是为什么呢。
其实原理一样,在传参的时候,将ao赋值给obj 那么此时obj也同样指向了ao指向的内存(js引用类型在做赋值的时候只是拷贝了一份值的地址,并不是重新开辟一个新的内存存储。)
所以这个时候修改obj的属性的时候就会影响到ao。因为他们俩本质上指向的是同一个内存地址。这个效果其实和浅拷贝的一样的。他并不是说函数内能修改原数据。只是恰巧引用类型的数据满足了这个运行机制而已。
当我们稍稍修改一下这个函数
function fs(obj){
obj = {
sex:null
}
}
在函数里给obj重新赋值一个新的对象。这个时候会输出什么呢
{name: 123}
此时实参并没有如我们想的那样也被修改成了{sex:null}。这也就证实了上面说的那些话。 给obj赋值一个新的对象的时候,此时会给他开辟一个新的内存空间。这个时候obj和ao就不在指向同一个内存了。所以,他也就没有影响到ao。而obj这个数据则在函数运行完就销毁掉了。
知识点:基本数据类型的赋值和引用数据类型的赋值,函数的参数传递是按值传递的而非按引用传递