在ECMAjavascript中,建立函数最经常使用的两个方法是函数表达式和函数声明,这二者的区别并非很明显。由于ECMA规范只明确了一点:函数声明必须带有标识符(identifier,也就是常说的函数名称),而函数表达式能够省略标识符。javascript
//函数声明 function 函数名称:必须 (函数参数:可选){}; //函数表达式 function 函数名称:可选(函数参数:可选){}
也就是说,若是没有函数名称,那么确定是函数表达式,经常使用于:java
var foo = function(){};
那么若是有函数名称的时候,就要根据上下文来判断了。
若是是做为赋值表达式的一部分的话,那就是表达式。
若是是被包含在一个函数体内,或者位于程序最顶部,那么就是声明。json
var foo = function(){};// 函数表达式 function foo (){}; // 函数声明 new function(){}; // 匿名类表达式 (function(){ function foo(){}; // 声明 由于位于函数体内 })();
还有一种不太常见的表达式写法,就是被括号括住的(function(){}),这是由于在括号是一个分组操做符,在它内部只能是表达式。浏览器
function foo(){};//函数声明 (function foo(){}) //函数表达式,由于位于分组操做符内部 try{ (var temp = 3); } catch(error){ alert(error); } //这里会抛出异常,由于在()中只能放入表达式,而var是声明。
一样的,在使用eval方法,将string类型的json字符串转换为对象的时候,使用eval('('+str +')')也是这个缘由。把str放在括号内,就可使编译器把"{}"解析成表达式而不是代码块。ide
表达式和声明还有一个很大的差别就是:声明会在同一个做用域内,最先的表达式执行前执行解析。即便函数声明在最后一行,也会优先解析。函数
alert(foo()); function foo(){ return "abc"; } //这也就是为何结果是"abc"的缘由,声明虽然写在下面,可是在alert表达式以前已经被执行了。 // 可是若是foo不是以声明的方式定义,而是以表达式的方式定义的话,就会出现问题了: alert(foo()); var foo = function(){ return "abc"; }; //Uncaught TypeError: foo is not a function 会出现这个错误,由于在alert调用foo的时候,foo并无被解析。
另外,虽然在条件语句内部可使用函数声明,可是并无人测试过兼容性,所以,若是须要“重载”函数,最好仍是使用表达式:测试
if(true){ function foo(){ } } else{ function foo(){ } } //这种写法存在必定风险,最好使用如下表达式的写法 var foo; if(true){ foo = function(){}; } else{ }
上面说了一堆函数声明和函数表达式的区别,如今终于言归正传说到正题了。能够看到,上面函数表达式的例子里面,都是没有名字的。调试
//常规写法: var foo = function(){}; //命名函数表达式: var foo = function f(){}; f就是这个表达式的名字,可是,它的做用域仅仅在于函数内部 var foo = function f(){ alert(typeof f); }; foo(); alert(f);//Uncaught ReferenceError: f is not defined
既然如此,命名还有什么用呢?
答案就是在调试的时候,能够很爽。。。。code
var f1 = function (){ return "abc"; }; var f2 = function(){ return f1() + "edf"; }; var f3 = function(){ return f2(); }; alert(f3());
能够看到,当使用命名表达式时,Call Stack会使用该名称。不然会自动起一个名字。能够确定的是,当状况复杂的时候,解析器并不会返回你指望的那个名字,这也就是为何要使用命名表达式的缘由。对象
var foo = function f(){}; alert(foo === f);// 结果是false,固然这个只有在低版本的ie浏览器下才会看到,正常状况下f应该是undefined
了解到这些bug之后,最好的解决方案就是:当标识符不存在。
由于自己就是方便调试的,那么代码里面直接无视就是最好的办法。
若是不想使用“命名”的方式的话,能够还有一种简单的方式来替代,就是在函数表达式中,定义一个函数声明,而后将这个函数声明返回。
var hasClassName = (function(){ var cache = {}; var _className = '(?:^|\\s+)' + className + '(?:\\s+|$)'; var re = cache[_className] || (cache[_className] = new RegExp(_className)); return re.test(element.className); } return hasClassName; })();