猿问

解释封装的匿名函数语法

解释封装的匿名函数语法

摘要

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


我所知道的

在JavaScript中,可以创建一个命名函数,如下所示:

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

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

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

您可以通过创建匿名函数封装代码块,然后将其封装在括号中并立即执行:

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

在创建模块化脚本时,这是非常有用的,以避免将当前范围或全局范围与潜在冲突的变量混淆起来-比如Grecemonkey脚本、jQuery插件等等。

现在,我明白为什么要这样做了。括号将内容括起来,只公开结果(我确信有更好的方法来描述),例如(2 + 2) === 4.


我不明白的是

但我不明白为什么这也不一样:

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

你能给我解释一下吗?


蝴蝶不菲
浏览 373回答 3
3回答

潇湘沐

它不起作用,因为它被解析为FunctionDeclaration,函数声明的名称标识符是强制性.当您用圆括号包围它时,它被计算为FunctionExpression,函数表达式可以命名也可以不命名。a的语法FunctionDeclaration看起来是这样的:function Identifier ( FormalParameterListopt ) { FunctionBody }和FunctionExpressions:function Identifieropt ( FormalParameterListopt ) { FunctionBody }如你所见Identifier(标识符)选择)标记FunctionExpression是可选的,因此我们可以有一个函数表达式,而不需要定义名称:(function () {     alert(2 + 2);}());或命名功能表达式:(function foo() {     alert(2 + 2);}());“家长”(正式名称为分组操作符)只能环绕表达式,并计算函数表达式。这两个语法结果可能是模棱两可的,它们看起来完全相同,例如:function foo () {} // FunctionDeclaration0,function foo () {} // FunctionExpression解析器知道它是否是FunctionDeclaration或者是FunctionExpression,取决于语境它出现的地方。在上面的示例中,第二个表达式是一个表达式,因为准算子也只能处理表达式。另一方面,FunctionDeclarationS实际上只能出现在所谓的“Program“代码,意思是全局作用域中的代码,以及FunctionBody其他功能。应该避免块内的函数,因为它们可能导致不可预测的行为,例如:if (true) {  function foo() {    alert('true');  }} else {  function foo() {    alert('false!');  }}foo(); // true? false? why?上面的代码实际上应该产生一个SyntaxError,因为Block只能包含语句(ECMAScript规范不定义任何函数语句),但大多数实现都是容忍的,只需使用第二个函数,即警报函数'false!'.Mozilla实现-Rhino,SpiderMonkey-有着不同的行为。它们的语法包含非标准语句,意味着函数将在运行时间,而不是在解析时,就像在FunctionDeclarationS.在这些实现中,我们将定义第一个函数。函数可以不同的方式声明,比较以下几点: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-命名函数表达式漏斗名称,分配给变量倍增:var multiply = function func_name(x, y) {     return x * y;};

汪汪一只猫

尽管这是一个老生常谈的问题和答案,但它讨论了一个至今仍有许多开发人员需要一个循环的主题。我无法计算我采访过的JavaScript开发人员中有多少人无法告诉我函数声明和函数表达式之间的区别和他不知道什么是立即调用的函数表达式。不过,我想提一提,一个非常重要的事情是,即使Premasagar给出了一个名称标识符,它的代码片段也不能工作。function someName() {     alert(2 + 2);}();这不起作用的原因是JavaScript引擎将其解释为一个函数声明,后面跟着一个完全不相关的不包含表达式的分组运算符,以及分组运算符必包含表达式。根据JavaScript,上面的代码片段相当于下面的代码片段。function someName() {     alert(2 + 2);}();我想指出的另一件事是,对于某些人来说,您为函数表达式提供的任何名称标识符在代码上下文中都是无用的,除了函数定义本身之外。var a = function b() {     // do something};a(); // worksb(); // doesn't workvar c = function d() {     window.setTimeout(d, 1000); // works};当然,在函数定义中使用名称标识符对于调试代码总是有帮助的,但这完全是另外一回事.*-)

慕的地8271018

伟大的答案已经发布了。但我要指出的是,函数声明返回一个空的完成记录:14.1.20-运行时语义:评估职能宣言 : function Binding标识符 ( Formalameters ) { 功能体 }回归NormalCompletion(空)这个事实并不容易观察,因为大多数尝试获取返回值的方法都会将函数声明转换为函数表达式。然而,eval显示:var r = eval("function f(){}");console.log(r); // undefined调用一个空的完成记录是没有意义的。怪不得function f(){}()不能工作。事实上,JS引擎甚至没有尝试调用它,括号被认为是另一个语句的一部分。但是,如果将函数包装在括号中,它将成为一个函数表达式:var r = eval("(function f(){})");console.log(r); // function f(){}函数表达式返回函数对象。因此你可以称之为:(function f(){})().
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答