最近想自学javascript,今天一边查书一边学着写一些简单的函数之类的东西,由于之前学过C语言,自然而然的想着js中是否也有像C里面的指针,引用形参之类的东西,于是想写个交换两个变量的值的函数(swap),然而似乎不太简单。
我在网上找到了一段如下的代码,
1 function swap(a,b) 2 // This function is come from internet. 3 // URL@ http://bbs.51js.com/thread-65058-1-1.html 4 { 5 var temp=a; 6 this.a=b; 7 this.b=temp; 8 };
发现运行结果似乎是正常的,当我给a,b赋值后调用这个函数,输出的确是把a,b的值交换了。然而这段代码是错误的,个人觉得这个错误很有意思,就mark一下。O(∩_∩)O~
至于为什么是错误的,帖子中名为“井底之蛙”的朋友解释了(当然我是初学,也不知道这个解释对不对,完不完整),但觉得挺有道理,姑且贴过来吧:
“不要混淆了自己,也误导了别人。
楼主不清楚javascript的function参数的值传递特点以及指针、引用的概念。所以才会问出这样的问题,答案很明确,swap是不能实现的。当然,你可以通过js语言动态特征,如:反射来变相地实现,比如海浪的提供的例子。
而楼上Rimifon的代码的思路不清晰:
function 不通过 new 的方式调用,其内部上下文中的this其实是指向 window 对象。所以上面例子场景中的function swap相当于:
function swap(a,b)
{
var temp=a;
window.a=b;
window.b=temp;
}
很明显,实际上你在function中写死了“全局”变量a,b的名称。swap 不能起到swap 参数a,b 的作用。”
我自己试了一下,再定义变量c,d,调用swap(c,d),发现调用的结果并不是交换c,d的值,而是把c,d的值赋给了a,b,并交换a,b的值,从这一点来看,a,b的确是全局变量,这样的函数是不能够达到我想要交换变量的作用的。
在帖子中,一位叫“海浪”的朋友给出了这样的方法:
1 <script> 2 function swap($a,$b) 3 { 4 var temp=eval($a); 5 eval($a+"="+$b); 6 eval($b+"=temp"); 7 } 8 var a=3,b=4; 9 swap("a","b"); 10 document.write(a+" "+b); 11 </script>
这段代码让我感兴趣的地方有三个,一个是美元符号$,一个是eval()方法,还有就是调用的方式(在调用时变量a要写出'a')。
关于美元符号$,网上的说法有的说是prototype.js中的,有的说是jQuery中的,这个我暂时搞不清楚(初学者嘛,先不要在一个点纠结太久,不然就卡死了),不过大部分的说法是:
“$() 方法是在DOM中使用过于频繁的 document.getElementById() 方法的一个便利的简写,就像这个DOM方法一样,这个方法返回参数传入的id的那个元素。
比起DOM中的方法,这个更胜一筹。你可以传入多个id作为参数然后 $() 返回一个带有所有要求的元素的一个 Array 对象。”
也就是说,美元符号$是函数 document.getElementById()的简写(个人也觉得写这个名字好长,好麻烦,哈哈)。下面是几个关于prototype.js的网址,内容还不错 one, two, three,mark一下,以后再详细去了解。有点跑题了,这里的美元符号$只是一个变量名字的定义,跟那个函数方法没有啥关系,目的是为了尽量避免重名,因为重名的话就无法达到交换变量的目的了。
关于eval(),先看看w3c中的解释,“eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码”,我的理解,eval()是执行其参数(字符串)中的命令的意思,所以上述函数大概是这样子的,当调用swap('a','b')时,在swap函数内部,首先是变量$a的值为‘a',变量$b的值为'b',然后执行var temp=eval($a)时,也就是执行eval('a'),即temp=a;(其实函数swap内找不到a,b,我想它可能是在找不到变量时就去this中找吧,当然这个我不确定),后面的代码也是如此,所以当输入参数为'a','b'时,实际执行的应该是
1 var temp=a; 2 a=b; 3 b=temp;
当参数为'c','d'时,实际执行的应该是
1 var temp=c; 2 c=d; 3 d=temp;
这样就达到了交换变量的作用了,但是,当输入的字符串恰好等于形参名时,情况就会出错,例如输入为'$a'和'$b'时,其代码的实际执行情况应该是这样的
1 var temp='$a'; 2 $a=$b; 3 $b=temp;
函数执行的结果是把$a='$b',$b='$a',并没有实现交换变量的值的功能。而且如果在另一个函数中定义了新的a,b,并调用这个swap,它并不会改变这个函数中的a和b的值,而是改变了最外层的a和b的值。
这样一来,调用的方式为什么不是a,而是'a'也就很清楚了,因为要调用eval的缘故,里面的参数要是string。
综上所述,这两种方法都不能够真正合理的实现swap的方法。