总结

你能解释一下在JavaScript中封装匿名函数的语法背后的原因吗?为什么这样工作:(function(){})();但这不是:function(){}();?


我所知道的

在JavaScript中,像这样创建一个命名函数:

function twoPlusTwo(){
    alert(2 + 2);
}
twoPlusTwo();

你也可以创建一个匿名函数并将其赋值给一个变量:

var twoPlusTwo = function(){
    alert(2 + 2);
};
twoPlusTwo();

你可以通过创建一个匿名函数来封装一个代码块,然后将它包装在括号中并立即执行:

(function(){
    alert(2 + 2);
})();

这在创建模块化脚本时非常有用,可以避免由于潜在的冲突变量而使当前作用域或全局作用域混乱——就像Greasemonkey脚本、jQuery插件等情况一样。

现在,我明白为什么这是可行的了。括号将内容括起来,只公开结果(我相信有更好的方式来描述它),例如(2 + 2)=== 4。


我不明白

但我不明白为什么这不能同样有效:

function(){
    alert(2 + 2);
}();

你能给我解释一下吗?


当前回答

(function(){
     alert(2 + 2);
 })();

以上是有效的语法,因为括号内传递的任何内容都被视为函数表达式。

function(){
    alert(2 + 2);
}();

以上语法无效。因为java脚本语法分析器在函数关键字之后查找函数名,因为它没有找到任何东西,所以抛出一个错误。

其他回答

我还有一个小问题。您的代码将工作与一个小的变化:

var x = function(){
    alert(2 + 2);
}();

我使用上面的语法,而不是更广泛的版本:

var module = (function(){
    alert(2 + 2);
})();

因为我没有设法让缩进工作正确的javascript文件在vim。似乎vim不喜欢左括号内的花括号。

尽管这是一个古老的问题和答案,但它讨论的主题至今仍使许多开发人员陷入困境。我无法计算我面试过的JavaScript开发人员候选人中有多少人不能告诉我函数声明和函数表达式之间的区别,也不知道立即调用的函数表达式是什么。

不过,我想提一点非常重要的事情,那就是Premasagar的代码片段即使给它一个名称标识符也不能工作。

function someName() {
    alert(2 + 2);
}();

这行不通的原因是JavaScript引擎将其解释为一个函数声明,后面跟着一个完全不相关的不包含表达式的分组操作符,而分组操作符必须包含一个表达式。根据JavaScript,上面的代码段等同于下面的代码段。

function someName() {
    alert(2 + 2);
}

();

我想指出的另一件可能对某些人有用的事情是,您为函数表达式提供的任何名称标识符在代码上下文中几乎毫无用处,除非在函数定义本身中。

var a = function b() {
    // do something
};
a(); // works
b(); // doesn't work

var c = function d() {
    window.setTimeout(d, 1000); // works
};

当然,在调试代码时,在函数定义中使用名称标识符总是有帮助的,但那完全是另一回事了……:-)

也许简短的回答是这样的

function() { alert( 2 + 2 ); }

是定义(匿名)函数的函数字面量。附加的()-对被解释为表达式,不需要在顶层,只需要字面量。

(function() { alert( 2 + 2 ); })();

在调用匿名函数的表达式语句中。

这些额外的圆括号在全局命名空间和包含代码的匿名函数之间创建了额外的匿名函数。在Javascript中,其他函数内部声明的函数只能访问包含它们的父函数的命名空间。由于在全局作用域和实际代码作用域之间存在额外的对象(匿名函数),因此不保留作用域。

(function(){
     alert(2 + 2);
 })();

以上是有效的语法,因为括号内传递的任何内容都被视为函数表达式。

function(){
    alert(2 + 2);
}();

以上语法无效。因为java脚本语法分析器在函数关键字之后查找函数名,因为它没有找到任何东西,所以抛出一个错误。