这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
下面小编就为大家带来一篇浅谈 js 中的引用和复制 (传值和传址)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
好像一般很少人讲到 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 的值的复制,其实和普通函数是一样的,不要因为加了闭包就迷糊了,回归本源去思考就明白了,本源就是上面讲到的传址的传递
顺便提一句,不要被闭包这个古怪的名字唬住了,其实它和我们平时用的函数原理是一样的,抛开那些 "更长的生命周期"" 保护私有变量 " 等闭包所谓的特性,把它当成一个普通的函数(也可以换个角度把全局函数看成一个特殊的闭包),很容易就可以理解了
关键是要放下所有的浮华,回归最本质。。。又跑题了。。。
以上这篇浅谈 js 中的引用和复制 (传值和传址) 就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持 phperz。
来源: http://www.phperz.com/article/17/0521/331794.html