解释封装的匿名函数语法 [英] Explain the encapsulated anonymous function syntax

查看:22
本文介绍了解释封装的匿名函数语法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can you explain the reasoning behind the syntax for encapsulated anonymous functions in JavaScript? Why does this work: (function(){})(); but this doesn't: function(){}();?

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

In JavaScript, one creates a named function like this:

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

您也可以创建匿名函数并将其分配给变量:

You can also create an anonymous function and assign it to a variable:

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

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

You can encapsulate a block of code by creating an anonymous function, then wrapping it in brackets and executing it immediately:

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

这在创建模块化脚本时很有用,以避免混淆当前范围或全局范围,以及潜在的冲突变量 - 例如 Greasemonkey 脚本、jQuery 插件等.

This is useful when creating modularised scripts, to avoid cluttering up the current scope, or global scope, with potentially conflicting variables - as in the case of Greasemonkey scripts, jQuery plugins, etc.

现在,我明白为什么会这样了.括号括起内容并仅显示结果(我相信有更好的方法来描述),例如 (2 + 2) === 4.

Now, I understand why this works. The brackets enclose the contents and expose only the outcome (I'm sure there's a better way to describe that), such as with (2 + 2) === 4.

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

But I don't understand why this does not work equally as well:

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

你能解释一下吗?

推荐答案

它不起作用,因为它被解析为 FunctionDeclaration,并且它的名称标识符函数声明是强制性.

It doesn't work because it is being parsed as a FunctionDeclaration, and the name identifier of function declarations is mandatory.

当你用括号将它括起来时,它被评估为一个 FunctionExpression,并且函数表达式可以命名或不命名.

When you surround it with parentheses it is evaluated as a FunctionExpression, and function expressions can be named or not.

FunctionDeclaration 的语法如下所示:

function Identifier ( FormalParameterListopt ) { FunctionBody }

FunctionExpressions:

function Identifieropt ( FormalParameterListopt ) { FunctionBody }

如您所见,FunctionExpression 中的 Identifier (Identifieropt) 标记是可选的,因此我们可以有一个没有名称的函数表达式定义:

As you can see the Identifier (Identifieropt) token in FunctionExpression is optional, therefore we can have a function expression without a name defined:

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

命名函数表达式:

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

括号(正式名称为分组运算符) 只能包围表达式,并计算函数表达式.

The Parentheses (formally called the Grouping Operator) can surround only expressions, and a function expression is evaluated.

这两个语法产生式可能有歧义,它们看起来可能完全一样,例如:

The two grammar productions can be ambiguous, and they can look exactly the same, for example:

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression

解析器知道它是 FunctionDeclaration 还是 FunctionExpression,具体取决于它出现的上下文.

The parser knows if it's a FunctionDeclaration or a FunctionExpression, depending on the context where it appears.

在上面的例子中,第二个是一个表达式,因为 逗号运算符也只能处理表达式.

In the above example, the second one is an expression because the Comma operator can also handle only expressions.

另一方面,FunctionDeclaration实际上只能出现在所谓的Program"中.代码,即全局作用域之外的代码,以及其他函数的FunctionBody 内的代码.

On the other hand, FunctionDeclarations could actually appear only in what's called "Program" code, meaning code outside in the global scope, and inside the FunctionBody of other functions.

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

Functions inside blocks should be avoided, because they can lead an unpredictable behavior, e.g.:

if (true) {
  function foo() {
    alert('true');
  }
} else {
  function foo() {
    alert('false!');
  }
}

foo(); // true? false? why?

上面的代码实际上应该产生一个 SyntaxError,因为一个 Block 只能包含语句(并且 ECMAScript 规范没有定义任何函数语句),但大多数实现是宽容的,并且只会采用第二个函数,警告 'false!' 的那个.

The above code should actually produce a SyntaxError, since a Block can only contain statements (and the ECMAScript Specification doesn't define any function statement), but most implementations are tolerant, and will simply take the second function, the one which alerts 'false!'.

Mozilla 实现——Rhino、SpiderMonkey——有不同的行为.它们的语法包含一个非标准函数语句,这意味着该函数将在运行时被评估,而不是在解析时,就像FunctionDeclarations.在这些实现中,我们将获得定义的第一个函数.

The Mozilla implementations -Rhino, SpiderMonkey,- have a different behavior. Their grammar contains a non-standard Function Statement, meaning that the function will be evaluated at run-time, not at parse time, as it happens with FunctionDeclarations. In those implementations we will get the first function defined.

函数可以用不同的方式声明,比较以下内容:

Functions can be declared in different ways, compare the following:

1- 使用分配给的 Function 构造函数定义的函数变量乘以:

1- A function defined with the Function constructor assigned to the variable multiply:

var multiply = new Function("x", "y", "return x * y;");

2- 名为 multiply 的函数的函数声明:

2- A function declaration of a function named multiply:

function multiply(x, y) {
    return x * y;
}

3- 分配给变量 multiply 的函数表达式:

3- A function expression assigned to the variable multiply:

var multiply = function (x, y) {
    return x * y;
};

4- 命名函数表达式 func_name,分配给变量 multiply:

4- A named function expression func_name, assigned to the variable multiply:

var multiply = function func_name(x, y) {
    return x * y;
};

这篇关于解释封装的匿名函数语法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆