js- 引用和复制(传值和传址)

转自:http://blog.csdn.net/zzzaquarius/article/details/4902235

好像一般很少人讲到js中的引用和复制,不过弄清楚这个概念可以帮助理解很多东西

先讲一下很基础的东西,看看js中几种数据类型分别传的什么

引用:对象、数组、函数

复制:数字、布尔

字符串单独说明,因为它的特殊性,无法确定是传递引用还是复制数值(因为字符串的值是没法改变的,所以纠结这个问题也是没意义的)但是用于比较的时候显然是属于传值比较(稍后具体说比较的事)

下面讲一下在使用中的具体体现

最普通的使用就是赋值了

var a = 1;

var b = a;  //赋的是a的复制值

b ++;

alert(a);  //"1"  b的修改不影响a

/****************************************/

var a = [1];

var b = a;    //赋的是a的引用

b[0] ++;

alert(a);  //"2"  b的修改对a也有效    不过当然b = [2];这种修改对a是没用的。。。。。。

函数的参数

传值的传递:传给函数的是数值的一个复制,函数中对其的修改外部不可见

var a = 1;

var b = 2;

function change(a,b) {

var c = a;

a = b;      //用新引用覆盖

b = c;

alert(a);  //"2"

alert(b);  //"1"

}

change(a,b);

alert(a);  //"1"

alert(b);  //"2"

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

var a = [1, 2, 3];

var b = [5, 6];

function change(a,b) {

a[0] = 4;    //对其属性的修改外部可见

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"

从结果可以看出a和b并没有互换  因为用新引用覆盖在外部不可见 这个很自然 因为函数只是拿到了引用 并没有权力更改引用

下面这个就不同了

var a = [1, 2, 3];

var b = [5, 6];

function change() {

var c = a;

a[0] = 4;

a = b;

b = c;

};

change();

alert(a);  //"5,6"

alert(b);  //"4,2,3"

这里成功实现互换

又得提到js的块级作用域了,这个放某些语言里定然是要报未定义错误的,因为js没有块级作用域,所以它在change里找不到变量a,b就会自觉的到上层去找,所以这里的a,b是全局变量的引用

而上面的那个a,b则是change函数中的变量,在调用函数时传递了a,b的引用赋给了这两个变量,但是并不能改变全局中的a,b,这里换个名字大概就好理解多了

这个稍微提下    有些走题了。。。。

回到引用和复制 在比较运算中的注意事项

传值的比较比较的是数值 而传址的比较比较的是引用,引用不同即使数值相同也不等

1 == 1;    //true

1 === 1;  //true

[0] == [0]; //false

[0][0] == [0][0];    //true

[0][0] === [0][0];  //true

[0].toString() == [0].toString();  //true

闭包中。。。。

闭包大概是js中最纠结的东西 我们部门面试的经典试题,常考不衰啊。。。。

这里我先不说闭包的东西,只说一下涉及传值和引用的部分,等我哪天确定自己可以用清晰的条例、简明的语言、生动的实例彻底的说清楚那个东西,再详细介绍这个提js不能不提的家伙。。。

闭包中,内部函数用外部函数的局部变量使用引用的方式而不是复制

其实这也是理解闭包的一个很重要的部分 可以用这个解释一个很经典的闭包现象,很多地方在说明闭包的时候都会用到的一个例子

/*构造一个函数,给数组中的节点设置事件处理程序,当点击一个节点时,alert出节点的序号*/

var add_handlers = function (nodes) {

var i;

for (i = 0, l = nodes.length; i < l; i ++) {

nodes[i].onclick = function (e) {

alert(i);    // 当然这里的结果必然是每次alert的都是节点总数。。。。

}

}

};

为什么每次alert的都是节点总数 而不是预期的序号呢,这个如果用复制和引用解释就相当容易了

因为内部函数在使用外部变量时使用引用的方式而不是复制,就是说我给每个节点设置onclick事件的时候将i的引用传递给了alert,当我点击节点触发onclick事件的时候,i的值已经变成了节点总数。。。

var add_handlers = function (nodes) {

var i;

for (i = 0, l = nodes.length; i < l; i ++) {

nodes[i].onclick = function (i) {

return function(){

alert(i);

}

}(i);

}

};

这样修改后之所以正确是因为此时传进去的是i的值的复制,其实和普通函数是一样的,不要因为加了闭包就迷糊了,回归本源去思考就明白了,本源就是上面讲到的传址的传递

顺便提一句,不要被闭包这个古怪的名字唬住了,其实它和我们平时用的函数原理是一样的,抛开那些“更长的生命周期”“保护私有变量”等闭包所谓的特性,把它当成一个普通的函数(也可以换个角度把全局函数看成一个特殊的闭包),很容易就可以理解了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,915评论 2 17
  • 《ijs》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 10...
    叶染柒丶阅读 5,375评论 0 7
  • 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 一、变量...
    zock阅读 1,085评论 2 6
  • 第一章: JS简介 从当初简单的语言,变成了现在能够处理复杂计算和交互,拥有闭包、匿名函数, 甚至元编程等...
    LaBaby_阅读 1,706评论 0 6
  • 一个喜欢的公众号推荐了一部电影,叫布鲁克林,是一个讲述远走他乡追梦,结果回到故乡已经无法适应的故事。因为自己也有类...
    by小微阅读 386评论 5 0