js有一些“神奇”特性。
1.函数参数
js的函数在定义的时候可以没有参数,但调用的时候传参也不会报错,也就是说函数参数的定义与函数实际调用没有半毛钱关系。之所以会这样,是因为ECMAScript中的参数在内部是用一个数组表示的。举个例子:
function add(){ if(arguments.length == 1){ alert(arguments[0]); }else if(arguments[1].length == 2){ alert(arguments[1] +arguments[0]); } }
当调用add(10)的时候直接输出10,调用add(10,20)的时候输出30.情况就是这样,不管你怎么传参,函数接收到的实际上是一个arguments数组。当然你也可以使用参数。一开始还以为js让第i个参数和arguments[i-1]指向了同一块内存空间。但事实上并非如此。他们的内存空间是独立的,只是arguments对象中的值会自动反应到对应的命名参数罢了。
2.没有重载
如果你定义了两个同名的函数,那么后一个函数很可能会覆盖前面的。其实还是之前说的问题。js函数是通过arguments对象操作参数的,你有定义多少参数都没意义,关键是你调用时传递多少参数。而函数的重载是通过同名参数的类型和数量来实现的,所以这就决定了js中没有传统意义上的重载。但你可以通过检查传入参数的个数和类型来模仿重载。就像上面的add()函数一样。有没有感觉这样还要简单一些?3.基本类型和引用类型
js中的五种基本类型:Undefinded、Null、Boolean、Number和String,他们都是按值访问的。引用类型的值是保存在内存中的对象,由于js不准直接访问内存中的位置,所以在操作对象时,实际上是在操作对象的引用。但当为对象添加属性时,操作的是实际的对象。所以如果当从一个变量向另外一个变量复制引用类型的值时,对一个变量修改属性,也会反映到另外一个变量身上,因为他们在堆内存中指向的是同一个对象。
var obj1=new Object(); var obj2=obj1; obj1.name="Lee"; alert(obj2.name);//弹出"Lee"
4.所有函数参数都是按值传递的!
先看一个例子:
function setName(obj){ obj.name="Lee"; } var person=new Object(); setname(person); alert(person.name);//弹出"Lee"不是按值传递么!为毛在函数内改变值函数外也会受影响!好吧,其实在传递参数给setname函数的时候复制了person变量,上面说了,这两个变量指向的是内存中的同一个对象,所以改变一个另外一个也会变!有很多人错误的以为:在局部作用域中修改的对象在全局作用域中反应出来就说明参数是按引用传递的。为了证明对象也是按值传递的,再看一个例子:
function setName(obj){ obj.name="Lee"; obj = new Object(); obj.name = "Yu"; } var person=new Object(); setname(person); alert(person.name);//弹出"Lee"如果person是按引用传递的,那么弹出的应该是Yu,而不是Lee。实际上在setname中对obj重写之前,obj与person指向的是同一个对象,重写之后,obj就是一个局部对象了,这个对象在函数执行完毕后被立即销毁。