天天看点

javascipt中函数传参的方式,按值传参还是按引用传参?什么是按值传递?什么是按引用传递?

什么是按值传递?什么是按引用传递?

按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。

按引用传递(call by reference)时,函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。

按值传递由于每次都需要克隆副本,对一些复杂类型,性能较低;按引用传递会使函数调用的追踪更加困难,有时也会引起一些微妙的BUG。

探究JS值的传递方式

JS的基本类型,是按值传递的,如下代码可以证明:

var a = 1;
function foo(x) {
    x = 2;
 }
foo(a);
console.log(a); // 仍为1, 未受x = 2赋值所影响
           

而对于引用类型来看如下代码:

var obj = {x : 1};
 function foo(o) {
     o.x = 3;
 }
 foo(obj);
 console.log(obj.x); // 3, 被修改了!
           

说明o跟obj指向的是同一个对象,所以不是按值传递的,但是这就能证明js中对象是按引用传递的吗??少年们可以看如下这个例子:

var foo = {name:'foo'};
 function test(o){
    o = {name:'bar'};  
 }
 test(foo);
 console.log(foo.name);
           

打印foo.name的值确还是'foo',这就说明js中对象的传递也不是不是按引用传递。好凌乱啊...那js中对象究竟是按什么传递呢?

按共享传递 call by sharing

严格的说,JS中的基本类型按值传递,对象类型按共享传递的(call by sharing,也叫按对象传递、按对象共享传递)。最早由Barbara Liskov. 在1974年的GLU语言中提出。该求值策略被用于Python、Java、Ruby、JS等多种语言。

该策略的重点是:调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。实质大家可以这么理解:

在调用函数传递引用类型的参数时,传递是是对象引用的副本,但是这个对象引用的副本跟原对象引用指向的是同一个地方(也就是该对象在内存中存放的地址),大家要认真理解这句话!!!!

大家看如下这个例子就印证了按共享传递的观点

var foo = {name:'foo'};
 function test(o){
   o.name='test';
   o={name:'bar'}    
 }
 test(foo);
 console.log(foo);
 //打印结果为:
 Object {name: "test"}
           

从上面结果可以得出第一:对象不是按值传递的,如果是按值传递的话打印出来的foo的name属性的值不会为test,因为按值传递的话传递的是对象的一个副本,对副本的修改不会影响元对象,所以可以证明对象不是按值传递的!

也可以证明第二:js中对象也不是完全按引用传递的,如果是按引用传递的话在执行o={name:'bar'}这行代码的时候,foo打印的结果应该是Obeject {name:'bar'}了,而结果确是Object {name:'test'},所以综上两点js引

用类型在作为参数传递时是按共享传递的,即传递是是原对象引用的一个副本,但是这个副本跟原对象的引用指向的都是内存中的对象!

转自https://www.cnblogs.com/QingChengFE/p/4543608.html

继续阅读