Javascript 匿名函数与闭包
一、函数的几种定义
1、函数关键字(function)语句
function func1(){
alert("func1");
}
func1();
2、函数直接量(Function Literals)
var func2 = function(){
alert("func2");
}
func2();
虽然函数直接量创建的是未命名函数,但是它的语法也规定它可以指定函数名。
var func4 = function func5(){
alert("func5");
}
func4();
函数直接量在编写调用自身的递归函数时非常有用。如:
var func6 = function fact(x) {
if (x <= 1 ) {
return 1 ;
} else {
return x * fact(x - 1 );
}
};
alert(func6(4));
上面的代码定义了一个未命名函数,并对它的引用存储在变量func6中。它并没有真正的创建一个名为fact()的函数,只是允许函数体用这个名字来引用自身。
但是要注意,JavaScript1.5之前的版本中没有正确实现这种命名的函数直接量。
3、使用Function对象构造函数
var func3 = new Function('x','y','var r = x + y;alert(r);');
func3(3,4);
Functino()构造函数可以接受任意多个字符串参数。它的最后一个参数是函数的主体,其中可以包含任何JavaScript语句,语句之 间用分号分隔。其他的参数
都是用来说明函数要定义的形式参数名的字符串。如果你定义的函数没有参数,那么可以只需给构造函数传递一个函数的主体字符串即可。
无论你用上述哪种方式去定义函数,JS解释器都会把它翻译成一个Function对象。这一点我们可以通过调用函数对象的constructor属性,进行验证。
alert(func1.constructor);
alert(func2.constructor);
alert(func3.constructor);
结果如下:
function Function() {
[native code]
}
二、匿名函数
什么是匿名函数
顾名思义,匿名函数就是没有实际名字的函数。从这个层面上来看,上述方式2和方式3什么时都没有指定函数的名字。都属于匿名函数。
方式2函数直接量创建的是未命名函数,而且不会自动地将这个函数存储在属性中。但是,比起Function() 构造函数来说,函数直接量有一个重要的优点。由
Function()构造函数创建的函数的主体必须用一个字符串说明,用这种方式来表达一个长而复杂的函数 是狠笨拙的。但是函数直接量的主体使用的却是标准的
JavaScript语法。而且函数直接量只被解析一次,而作为字符串传递给Function()构造 函数的JavaScript代码则在每次调用构造函数时只需被解析一次和编译一次。
匿名函数的调用
要调用一个函数,我们必须要有方法定位它,引用它。
1)将函数赋值给某一变量对它进行引用;
var abc=function(x,y){
return x+y;
}
alert(abc(2,3)); // "5"
2)使用()将匿名函数括起来,然后后面再加一对小括号(包含参数列表)
(function($) {
//jQuery 代码实现部分
})(jQuery);
这是我们在jQuery中看到的代码片段。
小括号能把我们的表达式组合分块,并且每一块,也就是每一对小括号,都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。所以,当我们用一对小括号把匿名函数括起来的时候,实际上小括号对返回的,就是一个匿名函数的Function对象。因此,小括号对加上匿名函数就如同有名字的函数般被我们取得它的引用位置了。所以如果在这个引用变量后面再加上参数列表,就会实现普通函数的调用形式。
3)优先表达式:由于Javascript执行表达式是从圆括号里面到外面,所以可以用圆括号强制执行声明的函数。
( function(){
alert(2);
} ( ) );
4)Void操作符:用void操作符执行一个没有用圆括号包围的一个单独操作数。
void function(){
alert(3);
}();
5) eval函数动态执行。
eval(function(){
alert(4);
}());
为什么要用匿名函数
“全局变量是魔鬼”。配合var关键字,匿名函数可以有效的保证在页面上写入Javascript,而不会造成全局变量的污染。这在给一个不是很熟悉的页面增加Javascript时非常有效,也很优美。当然对于我个人而言,还是习惯采用面向对象的思想去避免变量重复,增强代码可读性。
三、闭包
闭包,其实是一种语言特性,它是指的是程序设计语言中,允许将函数看作对象,然后能像在对象中的操作搬在函数中定义实例(局部)变量,而这些变量能在函数中保存到函数的实例对象销毁为止,其它代码块能通过某种方式获取这些实例(局部)变量的值并进行应用扩展。是否应用了闭包特性,必须确定该段代码有没有最重要的要素:未销毁的局部变量。那么很显然,没有任何实现的匿名函数不可能应用了闭包特性。但如果匿名函数 里面有实现呢?那也还得确定它的实现中有没有用到那些未销毁的局部变量。
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。例如:
function closure(){
var x = 10;
setTimeout(
function(){ alert( x ); } //匿名函数
, 1000);
}
closure ();
在该示例中closure函数瞬间执行完毕,正常情况下x变量应该得到释放。但由于内嵌的匿名函数中有对x变量的引用。所以必须等1000ms后匿名函数执行完毕后,x变量所占用的资源才得到释放。
闭包应用
function doAdd( x, y){
alert( x + y );
}
function doSetTimeout( x , y , time ){
setTimeout(doAdd (' + x + ',' + y + ')' , time );
}
上面的doSetTimeouty函数十分难以阅读,也不容易编写,但如果使用闭包就可以让代码更加清晰。
function doSetTimeout ( x , y , time ){
setTimeout(
function(){
doAdd( x , y )
}
, time );
}