纯牛奶645
纯牛奶645
  • 发布:2017-07-20 11:53
  • 更新:2017-07-20 11:53
  • 阅读:2920

javaScript的按值传递和按引用传递

分类:Native.js

按值传递(call by value)是最常用的求值策略:函数的形参是被调用时所传实参的副本。修改形参的值并不会影响实参。
按引用传递(call by reference)时,函数的形参接收实参的隐式引用,这意味着函数形参的值如果被修改,实参也会被修改。同时两者指向相同的值。

按引用传递会使函数调用的追踪更加困难,有时也会引起一些微妙的bug。

按值传递由于每次都需要克隆副本,对一些复杂类型,性能较低。两种传递方式都有各自的问题。
js的基本类型是按值传递的。(基本类型:string、boolean、)
var a = 1;
function foo(x){
x =2;
}
foo(a);
console.log(a);//仍为1,未受x = 2赋值所影响

再来看看对象传值:(对象类型:obj,array)
var obj = {x :1};
function foo(ob){
ob.x = 3;}
foo(obj);
console.log(obj.x);//3,被修改了!
var obj = {x : 1};
function foo(ob){
ob = 100;
}
foo(obj);
console.log(obj.x);//仍然是1,obj未被修改为100.

可以看出,对象的传值并不是按引用传递。其实,按共享传递call by sharing,准确的说,js中的基本类型按值传递,对象类型按共享传递的,也叫按对象传递、按对象共享传递。该求值策略被用于python/java/puby/js等多种语言。
该策略(按对象传递、按对象共享传递)的重点是:调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。代码如下;

var obj = {x : 1};
function foo(ob){
ob = 100;
}
foo(obj);
console.log(obj.x);//仍然是1,obj未被修改为100.

然而,虽然引用是副本,引用的对象是相同的。他们共享相同的对象,所以修改形参对象的属性值,也会影响到实参的属性值。如下:
var obj = {x :1};
function foo(ob){
ob.x = 3;}
foo(obj);
console.log(obj.x);//3,被修改了!

按引用传递相当于一个是有名字的框,框里有各种各样的东西(对象)。框可以有不同的名字,但里面的内容还是同一个内容。相当于有了两把钥匙。

对于对象类型,由于对象是可变mutable的,修改对象本身会影响到共享这个对象的引用和引用副本。

而对于基本类型,由于他们都是不可变immutable的,按共享传递与按值传递没有任何区别,所以说js基本类型既符合按值传递,也符合共享传递。
var a = 1; // 1是number类型,不可变 var b = a; b = 6;

据按共享传递的求值策略,a和b是两个不同的引用(b是a的引用副本),但引用相同的值。由于这里的基本类型数字1不可变,所以这里说按值传递、按共享传递没有任何区别。

基本类型的不可变(immutable)性质
基本类型是不可变的(immutable),只有对象是可变的(mutable). 例如数字值100, 布尔值true, false,修改这些值(例如把1变成3, 把true变成100)并没有什么意义。比较容易误解的,是JS中的string。有时我们会尝试“改变”字符串的内容,但在JS中,任何看似对string值的”修改”操作,实际都是创

建新的string值。代码如下:
var str = “abc”;
str[0];//"a"
str[0] = "d";
str;//仍然是“abc”,赋值时无效的。没有任何办法修改字符串的内容
而对象就不一样了,对象是可变的。代码如下:
var obj = {x:1};
obj.x = 100;
var ob = obj;
ob.x = 1;
obj.x;//1,被修改
ob = true;
obj.x;//1,不会因ob = true改变。
这里定义变量obj,值是object,然后设置obj.x的属性值为100.而后定义另一个变量ob,值仍然是这个object对象,此时obj和ob两个变量指向同一个对象(共享同一个对象的引用)。所以修改对象的内容,对obj和ob都有影响。但对象并非按引用传递,通过ob=true修改了ob的值,不会影响obj。

    总之,基本类型是按值传递,而对于对象来说传入的是对象指向的地址,也可以认为其是特殊的按值传递。如果在函数内对象的属性进行操作,实际就是对其指向对象的属性进行操作。但是,如果对其整体进行操作(比如:ob = 100或者ob = 【】),其实际是新定义了对象,实参的引用地址为新的对象的引用地址,与原来的引用没有任何关系,所以不会对原来的对象造成改变。  

传递的两种类型:
1.按值传递:string number boolean 基本类型,变量创建了一个新的内存副本,改变形参并不会修改实参的值。
2.按引用传递:object array 对象类型,对象指向同一个地址,就是内存地址,可以类比为门牌号,对象类型的值是地址而不是真正对象本身。可直接修改实参的值。
参考:http://www.jb51.net/article/60568.htm

0 关注 分享

要回复文章请先登录注册