关于JS中的引用和复制(传值和传址)

来源:互联网 发布:南京大学软件学院科技 编辑:程序博客网 时间:2024/06/11 17:49

先来介绍一下按值传递与按引用传递

按值传递:

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

按引用传递:

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

首先,在传递的时候,JS这几种数据类型分别传递的是什么:
引用:函数、数组、对象(其实函数和数组也是对象)
复制:数字、布尔
由于字符串的特殊性,无法确定是传递引用还是复制数值(因为字符串的值是没法改变的)但是用于比较的时候显然是属于传值比较。

接下来讲一下在使用中的具体表现:

1、赋值:
var a = 10;var b = a;b += 10;alert(a);//返回10,显然,改变b的值不会影响到a的值

————————————————————————————————————————

var a = [10,20,30];//定义a是一个数组var b = a;b[0] += 10;alert(a);//返回20,20,30,b的值改变影响到a的值

由于数组是引用类型,因此变量 a 其实存的是数组的指针,把数组的指针赋值给 b,那么 b 指向的也是 a 所指向的那片内存,指向的是同一个数组。因此修改 b 也会影响到 a。

2、函数的参数:

传值的传递:传给函数的是数值的一个复制(就是:形参是实参的一个副本),函数中对其的修改外部不可见:

var a = 10;var b = 20;function change(a,b){    var c = a;    a = b;    b = c;    alert(a);//返回 20    alert(b);//返回 10}change(a,b);alert(a);//返回 10alert(b);//返回 20

change(a,b)中的 a 和 b 其实就是传进来的 a 和 b 的一个副本(复制),换个名字就好理解了:

var a = 10;var b = 20;function change(c1,c2){    var c = c1;    c1 = c2;    c2 = c;    alert(c1);//返回 20    alert(c2);//返回 10}change(a,b);alert(a);//返回 10alert(b);//返回 20

传址的传递:传给函数的是数值的一个引用,函数中对其属性的修改外部可见,但用新引用覆盖其则在外部不可见,比如:

var a = [10, 20, 30];//数组,引用类型var b = [50, 60];function change(a,b) {  a[0] = 40;    //对其属性的修改外部可见    var c = a;  a = b;      //用新引用覆盖  b = c;  alert(a);   //返回"5,6"           alert(b);   //返回"4,2,3"}change(a,b);alert(a);    //返回"4,2,3"alert(b);     //返回"5,6"

看不明白?我们换个名字:

var a = [10,20,30];var b = [40,50];function change(c1,c2){    c1[0] = 40;    var c = c1;    c1 = c2;    c2 = c;    alert(c1);//返回 "40,50"    alert(c2);//返回 "40,20,30"}change(a,b);alert(a);//返回 "40,20,30"alert(b);//返回 "40,50"

当调用change(a,b)时,c1获得了[10,20,30]的地址,c1获得了[40,50]的地址,c1[0]=40,c1直接就在内存地址中修改了[10,20,30]的第一个值,没有经过 a ,因此在后面执行alert(a)的时候,[10,20,30]已被改成[40,20,30]。同时,由于c1和c2是 a,b 的复制,因此在函数里面怎么换,全局变量 a,b 都不会发生改变。注意,函数里面的 c 是局部变量,在函数执行完之后就被销毁了。

下面这个就不同了

var a = [10, 20, 30];var b = [50, 60];function change() {  var c = a;  a[0] = 40;  a = b;  b = c;};change();alert(a);   //"50,60"alert(b);   //"40,20,30"

由于函数没有形参,在函数体里面操作的直接就是全局变量,即 a 和 b 的本身,因此也就改变了他们原来的指向。

在这里得提到JS中的块级作用域问题了。这种情况要是放某些语言里定然是要报未定义错误的,因为js没有块级作用域,所以它在change里找不到变量a,b就会自觉的到上层去找,所以这里的a,b是全局变量的引用
而上面的例子中那个a,b则是change函数中的变量,在调用函数时传递了a,b的引用赋给了这两个变量,但是并不能改变全局中的a,b,我们可以采取在函数中命名变量尽量不要和全局变量相同就好理解了。

最后,此文章大多参考自http://blog.csdn.net/zzzaquarius/article/details/4902235

0 0
原创粉丝点击