解释封装的匿名函数语法

2022-08-29 23:28:41

总结

你能解释一下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);
}();

你能给我解释一下吗?


答案 1

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

当它用括号括起来时,它被计算为 FunctionExpression,函数表达式可以命名或不命名。

的语法如下所示:FunctionDeclaration

function Identifier ( FormalParameterListopt ) { FunctionBody }

和 s:FunctionExpression

function Identifieropt ( FormalParameterListopt ) { FunctionBody }

如您所见,(标识符选择)标记是可选的,因此我们可以有一个不定义名称的函数表达式:IdentifierFunctionExpression

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

命名函数表达式:

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

括号(正式称为分组运算符)只能将表达式括起来,并计算函数表达式。

这两种语法作品可能模棱两可,并且它们看起来可能完全相同,例如:

function foo () {} // FunctionDeclaration

0,function foo () {} // FunctionExpression

解析器知道它是 a 还是 a,这取决于它出现的上下文FunctionDeclarationFunctionExpression

在上面的示例中,第二个是表达式,因为逗号运算符也可以只处理表达式。

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

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

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

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

上面的代码实际上应该生成一个 ,因为 Block 只能包含语句(并且 ECMAScript 规范没有定义任何函数语句),但大多数实现都是容许的,并且会简单地采用第二个函数,即发出警报的函数。SyntaxError'false!'

Mozilla实现 - Rhino,SpiderMonkey,- 具有不同的行为。它们的语法包含一个非标准的函数语句,这意味着函数将在运行时进行计算,而不是在解析时进行计算,就像在 s 中发生的那样。在这些实现中,我们将定义第一个函数。FunctionDeclaration


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

1- 使用赋给变量法的函数构造函数定义的函数:

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

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

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

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

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

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

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

答案 2

尽管这是一个古老的问题和答案,但它讨论的主题直到今天仍然让许多开发人员陷入循环。我无法计算我采访过的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
};

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