Javascript 解释封装的匿名函数语法 总结

Javascript 解释封装的匿名函数语法 总结,javascript,syntax,anonymous-function,Javascript,Syntax,Anonymous Function,您能解释一下JavaScript中封装的匿名函数语法背后的原因吗?为什么这样做:(function(){})()但这不是:函数(){}() 我所知道的 在JavaScript中,可以创建如下命名函数: function twoPlusTwo(){ alert(2 + 2); } twoPlusTwo(); function Identifier ( FormalParameterListopt ) { FunctionBody } 还可以创建匿名函数并将其分配给变量: var tw

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


我所知道的 在JavaScript中,可以创建如下命名函数:

function twoPlusTwo(){
    alert(2 + 2);
}
twoPlusTwo();
function Identifier ( FormalParameterListopt ) { FunctionBody }
还可以创建匿名函数并将其分配给变量:

var twoPlusTwo = function(){
    alert(2 + 2);
};
twoPlusTwo();
通过创建匿名函数,然后将其包装在括号中并立即执行,可以封装代码块:

(function(){
    alert(2 + 2);
})();
这在创建模块化脚本时非常有用,以避免当前作用域或全局作用域与潜在冲突的变量混淆——例如Greasemonkey脚本、jQuery插件等

现在,我明白了为什么会这样。括号中包含内容,只显示结果(我相信有更好的方法来描述),例如使用
(2+2)==4


我不明白的是 但我不明白为什么这不起同样的作用:

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

你能给我解释一下吗?

它不起作用,因为它被解析为
函数声明,并且函数声明的名称标识符是必需的

当用括号将其括起来时,它将作为函数表达式计算,函数表达式可以命名也可以不命名

函数声明的语法如下所示:

function twoPlusTwo(){
    alert(2 + 2);
}
twoPlusTwo();
function Identifier ( FormalParameterListopt ) { FunctionBody }
FunctionExpression
s:

function Identifieropt ( FormalParameterListopt ) { FunctionBody }
正如您可以看到的那样,
FunctionExpression
中的
Identifier
(Identifieropt)标记是可选的,因此我们可以有一个没有定义名称的函数表达式:

(function () {
    alert(2 + 2);
}());
或命名函数表达式:

(function foo() {
    alert(2 + 2);
}());
括号(形式上称为)只能围绕表达式,函数表达式将被求值

这两个语法产品可能是不明确的,它们看起来可能完全相同,例如:

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression
解析器知道它是
FunctionDeclaration
还是
FunctionExpression
,这取决于它出现的上下文

在上面的示例中,第二个是表达式,因为也只能处理表达式

另一方面,
FunctionDeclaration
s实际上只能出现在所谓的“
Program
”代码中,这意味着代码在全局范围之外,在其他函数的
FunctionBody
内部

应避免使用块内的函数,因为它们可能导致不可预测的行为,例如:

if(真){
函数foo(){
警报(“真”);
}
}否则{
函数foo(){
警报('false!');
}
}

foo();//是吗?假的?为什么?
我还有一句话要说。您的代码只需稍作更改即可工作:

var x = function(){
    alert(2 + 2);
}();
我使用上述语法,而不是更广泛的版本:

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

因为我没有成功地使缩进在vim中对javascript文件正常工作。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 ); })();
位于调用匿名函数的表达式语句中

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

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

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

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

伟大的答案已经发布。但我想指出的是,函数声明返回一个空的完成记录:

函数声明:
function
BindingIdentifier
FormalParameters
{
FunctionBody
}

  • 返回(空)
  • 这一事实不容易观察到,因为尝试获取返回值的大多数方法都会将函数声明转换为函数表达式。但是,
    eval
    显示:

    var r=eval(“函数f(){}”);
    console.log(r);//未定义的
    它们可以与以下参数一起使用

    var x = 3; 
    var y = 4;
    
    (function(a,b){alert(a + b)})(x,y)
    

    在javascript中会产生7,这称为

    为了使其成为函数表达式,您必须:

  • 使用()将其括起来。

  • 在其前面放置一个空操作符

  • 将其分配给变量。

  • 否则,它将被视为函数def
    (function(arg1, arg2){
    //some code
    }(var1, var2));
    
    void function(arg1, arg2){
    //some code
    }(var1, var2);
    
      var ll = function (arg1, arg2) {
          console.log(arg1, arg2);
      }(var1, var2);
    
    ! function() { console.log('yeah') }()
    
    !! function() { console.log('yeah') }()