JavaScript函数传参原理详解——值传递还是引用传递

讨论JavaScript的传参原理之前,我们先来看一段曾经让笔者困惑了一段时间的代码

var testA=1;
var testB={};
function testNumber(example){
    example=2;
}

function testObj(example) {
    example.test=1;
}

testNumber(testA);
testObj(testB);
console.log(testA);//输出1
console.log(testB);//输出{test:1}

上述代码展示了一个比较纠结的问题:传入一个变量到函数中,函数对这个变量进行修改,到底会不会影响到原变量?从上面的代码我们可以发现,两者都可能出现。那到底是为什么呢?

解答这个问题之前,我们先来了解一下编程语言中函数传参的常用方式

穿插科普——实参和形参

所谓形参,是指我们定义函数的时候,函数定义的参数,例如上述代码中,testNumber函数定义中,example就是形参。

所谓实参,是指我们调用函数的时候,实际传入的值,例如上述代码中,testNumber(testA),此时testA为实参。

按值传递

按值传递是一种比较容易理解又使用比较广泛的传参方式,这种方式在传参的时候,在内存中会直接把实参的值复制一份再把副本传递给形参,对于形参的修改并不会影响到实参

按引用传递

按引用传递相对来说比较难理解,如果函数使用按引用传递,那么形参将会直接接收实参的引用,而不经过复制,那么此时对于形参的修改则会影响到实参。难以理解?看图(注意,图示仅为举例用于说明按引用传递,事实上图示的情况在js中并不会出现,具体原因下文会有说明)

由于在js中,引用类型在内存中分两部分存放,实际的值存放在堆中,在栈中会存放引用类型位于堆中的地址,而我们平时操作的,都是通过栈中的地址对对象进行操作的,那么如果使用按引用传递,就意味着操作的是同一个地址,对于形参的修改就会影响到实参

js中的传参策略

那么按照上面的分析,可能会有人认为,在js中,对于值类型是按值传递,对于引用类型是按引用传递,然而,这是错误的。事实上,在js中,不管对于值类型还是引用类类型,都是按值传递的,区别在于,对于值类型,传参发生时,复制的是类型本身的值,而对于引用类型,复制的是类型的地址。我们来看下面这段代码,可以用来否定引用类型是按引用传参这个观点

var testC={};
function testObject(example){
    example={b:1};
}
testObject(testC)
console.log(testC);//输出{},实参并没有改变

通过上面的代码我们可以看出,如果是按引用传参,那么直接修改形参,是会对实参造成影响的,但是我们发现事实上并没有,为了方便理解,下面给出JavaScript中值类型和引用类型进行传参时在内存中的实际复制情况

值类型

引用类型

总结

对于js中的变量,值类型存放在栈中,引用类型的地址存放在栈中,对应的值存放在堆中。当传参发生的时候,值类型会直接将栈中的值进行复制,形参和实参此时实际上是两个完全不相干的变量。对于引用类型,传参发生时,会将实参变量位于栈中的地址进行复制,此时栈中会有两个指向同一个堆地址的指针。

啰嗦一下对比testObj和testObject两个函数的不同效果

我们回头看一下上面举例的两个函数,都是直接对形参进行修改,为什么一个影响到了实参,而另一个却完全没有影响呢?为了方便对比,我们把它们放到一起

var testB={};
var testC={};
function testObject(example){
    example={b:1};
}

function testObj(example) {
    example.test=1;
}


testObject(testC);
testObj(testB);
console.log(testC);//输出{}
console.log(testB);//输出{test:1}

事实上,由于对引用对象的地址复制,形参和实参之间还是存在关联的,地址指向了同一个对象,也就是说我们调用testObj操作形参时,对应操作的对象也是实参。但是调用testObject时,就是另一种状况了,当我们直接将形参替换成另一个值,在内存中会形成下图的情况

此时,形参会指向堆中的另一个值,形参和实参从此彻底分道扬镳,无论怎么修改,都不会互相影响了

如有不同看法,欢迎留言指教

  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值