为什么调用匿名函数表达式有两种不同的语法?
我刚刚阅读了Ben Alman关于立即调用函数表达式,并对这部分感到好奇,他在其中引入了函数表达式和闭包(与 IIFE 还没有真正相关):
// ...难道函数表达式本身就可以 // 只需在其后面加上 () 即可调用? function(){ /* 代码放在这里 */ }(); // 这有效!嗯,差不多了。实际上是一个小的 JavaScript 语法问题 // 要求函数声明和函数之间存在歧义 // 消除表达式,这可以通过包装函数来完成 // 括号中的表达式。 // 以下模式普遍用于创建匿名 // 以“隐私”结束: (function(){ /* 代码放在这里 */ })(); // 这个括号语法也是有效的(我更喜欢以前的版本): (function(){ /* 代码放在这里 */ }());
最后一部分让我印象深刻。谁能解释为什么调用函数表达式有两种不同的语法版本?
这种语法是有意识地引入的,只是为了调用匿名闭包吗?或者它是其他语法属性的副产品?
为什么第二个版本仍然有效?从解析器的角度来看,第一个对我来说是有意义的。第一对括号计算为函数对象,第二对括号调用该函数对象。但第二个呢?它看起来并没有解决提到的语法歧义。
有人能告诉我我在这里缺少什么吗?
I just read Ben Alman's article on Immediately-Invoked Function Expressions and wondered about this part, where he's introducing function expressions and closures (not really related to IIFEs yet):
// ...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 */ }());
That last part struck me. Can anybody explain why there are two different syntactical versions for invoking function expressions?
Was this syntax consciously introduced just for invoking anonymous closures? Or is it a by-product of some other syntactical property?
Why does the second version work anyway? The first one makes sense to me from a parser standpoint. The first pair of parens evaluates to a function object, the second pair invokes this function object. But the second one? It doesn't look like it's resolving the mentioned syntactical ambiguity.
Can anybody tell me what I'm missing here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
所有这一切的发生都是因为 JavaScript 有两个解析上下文:表达式和语句。在语句级别编写
function foo() {}
会在该范围内定义函数foo
,而在表达式级别编写function foo() {}
则计算结果为一个新的匿名函数(可以递归地调用自身作为foo
)。因此,每当遇到该构造时,解析器都必须确定它是在表达式级别还是语句级别。默认情况下,它假定处于语句级别,除非另有说服力。括号是表示“这是一个表达式”的语法方式。
因此,编写
(function() {})
会使解析器将函数视为表达式。由于表达式只能包含其他表达式(没有语句),因此如果您编写(something-that-contains function(){} and-other-stuff)
那么其中的函数仍然会被视为一个表达式。All of it happens because JavaScript has two parsing contexts : expression and statement. Writing
function foo() {}
at statement level defines functionfoo
in that scope, whereasfunction foo() {}
at expression level evaluates to a new anonymous function (that can call itself recursively asfoo
).So, whenever that construct is encountered, the parser must determine whether it is at expression or statement level. By default, it assumes to be at statement level, unless convinced otherwise. The brackets are a syntactic way of saying "this is an expression".
So, writing
(function() {})
causes the parser to treat the function as an expression. Since expressions can only contain other expressions (no statements), it also follows that if you write(something-that-contains function(){} and-other-stuff)
then the function in there will still be treated as an expression.第二个之所以有效,是因为括号中的表达式不能解释为函数声明(因此它必须是函数表达式,解决了原始第一个表达式的歧义问题)。
The second one works because an expression in brackets cannot be interpreted as a function declaration (so it must be a function expression, resolving the ambiguity problem with the original first expression).