为什么有两种不同的语法来调用匿名函数表达式?

时间:2010-11-28 15:47:09

标签: javascript syntax closures

我刚刚阅读了Ben Alman关于Immediately-Invoked Function Expressions的文章,并想知道这部分,他正在介绍函数表达式和闭包(还没与IIFE真正相关):

// ...doesn't it stand to reason that the function expression itself can
// be invoked, just by putting () after it?

function(){ /* code goes here */ }();

// This works! Well, almost. A minor JavaScript syntax issue actually
// requires that ambiguity between function declarations and function
// expressions be eliminated, which can be done by wrapping the function
// expression in parens.

// The following pattern is used universally to create an anonymous
// closure with "privacy":

(function(){ /* code goes here */ })();

// This parens syntax is also valid (I prefer the previous version):

(function(){ /* code goes here */ }());

最后一部分让我感到震惊。任何人都可以解释为什么有两种不同的语法版本来调用函数表达式吗?

是否有意识地引入了这种语法来调用匿名闭包?或者它是其他一些句法属性的副产品?

为什么第二个版本还能正常工作?从解析器的角度来看,第一个对我有意义。第一对parens计算为函数对象,第二对调用此函数对象。但第二个?它看起来并不像是解决了上面提到的语法模糊性。

有人能告诉我这里缺少什么吗?

2 个答案:

答案 0 :(得分:3)

所有这一切都是因为JavaScript有两个解析上下文:表达式和语句。在语句级别编写function foo() {}定义该范围内的函数foo,而表达式级别的function foo() {}求值为新的匿名函数(可以递归调用自身为foo)。

因此,每当遇到该构造时,解析器必须确定它是在表达式还是语句级别。默认情况下,它假定为语句级别,除非另有说服力。括号是一种句法方式,表示“这是一个表达式”。

因此,编写(function() {})会导致解析器将函数视为表达式。由于表达式只能包含其他表达式(无语句),因此如果您编写(something-that-contains function(){} and-other-stuff),那么其中的函数仍将被视为表达式。

答案 1 :(得分:1)

第二个有效,因为括号中的表达式不能解释为函数声明(因此它必须是函数表达式,解决原始第一个表达式的歧义问题)。