在Javascript定义一个函数一般有如下三种方式:
函数关键字(function)语句:
function fnMethodName(x){alert(x);}
函数字面量(Function Literals):
var fnMethodName = function(x){alert(x);}
Function()构造函数:
var fnMethodName = new Function('x','alert(x);')
匿名函数,就是没有名字的函数。如:
function (){ alert('a function');}
但是,上面的代码会报错。firebug提示:function statement requires a name,也就是:函数必须要有个名字。
奇怪的是,如果我用一对()把这个没有名字的函数包起来,就不会报错了。如:
(function (){ alert('a function');})
(注意包裹函数的()!).虽然这样不会报错,但谁能知道这个函数是否声明成功了呢?是不是因为根本没声明所以才不报错呢?我们这样来测试:让函数自己执行一次:
(function (){ alert('a function');}())
可以看到,函数执行了,表明函数是存在的。
同样,如果这个时候去掉包裹函数的(),则依然会报前面那个错,函数也执行不了。。。
function (){ alert('a function');}()
匿名函数
先撇开Google的代码,看一下JavaScript其实是支持这种形式的行数定义的:
function(msg){ alert(msg); }("http://www.hzhuti.com/nokia/5236/");
这其实是两步:第一步,定义了一个函数,
相当于:
var abc = function(msg) { alert(msg);}
第二步,立刻执行它:
abc("hello world");
把两个语句拼接在一起,然后去掉abc这个函数的名字,就成了现在的语法形式。
封装
另外的一个好处,有可能是为了更好的封装。比如在这个函数里面,有很多的函数定义,比如
q(); p(); m(); g(); i()
还有大量的变量:
var j; var h; var l;
等等。在JavaScript里面没有简单的private这样的定义私有函数或者私有函数的方法。如果调用者可以随心所欲的访问到这些中间的(随时可能变化,甚至移除)成员。对于这么一个开肠破肚,一览无余的对象,从一个API提供者的角度来看(和使用者的角度来看),的确是个挺恐怖的事情。
如果放在一个匿名的函数里面,外界就再也没有办法直接访问到里面的函数了。内部的逻辑被完美的封装了起来。这样一来,这些函数和变量多么的安全!
函数字面量和Function()构造函数的区别
虽然函数字面量是一个匿名函数,但语法允许为其指定任意一个函数名,当写递归函数时可以调用它自己,使用Function()构造函数则不行。
var f = function fact(x) {
if (x < = 1) return 1;
else return x*fact(x-1);
};Function()
构造函数允许运行时Javascript代码动态的创建和编译。在这个方式上它类似全局函数eval()。
Function()构造函数每次执行时都解析函数主体,并创建一个新的函数对象。所以当在一个循环或者频繁执行的函数中调用Function()构造函数的效率是非常低的。相反,函数字面量却不是每次遇到都重新编译的。
用Function()构造函数创建一个函数时并不遵循典型的作用域,它一直把它当作是顶级函数来执行。
var y = "global";
function constructFunction() {
var y = "local";
return new Function("return y"); // 无法获取局部变量
}
alert(constructFunction()()); // 输出 "glob