立即执行函数调用语法

114

有一个JSLint选项,事实上是“好部分”之一,它“要求在立即调用周围使用括号”,这意味着该结构:

(function () {

  // ...

})();

需要写成以下形式:

(function () {

  // ...

}());

我的问题是 - 有人能解释一下为什么第二种形式被认为更好吗?它更有弹性吗?更少出错?它比第一种形式有什么优势?


自从我提出这个问题后,我已经明白了在函数值和函数的值之间具有清晰的视觉区别的重要性。考虑立即调用结果是赋值表达式右侧的情况:

var someVar = (function () {

  // ...

}());

虽然最外层的括号在语法上并不必要,但是左括号表明被赋值的值 不是 函数本身,而是函数被调用后的结果。

这类似于Crockford关于构造函数首字母大写的建议 - 它旨在为查看源代码的任何人提供视觉提示。


谢谢您指出这一点。我从未找到过如何摆脱JSLint的警告信息“在循环内创建函数时要小心。”我很小心,确实将函数放在了闭包中,但JSLint仍然抱怨。现在我知道它假设我使用了第二种模式。 - viam0Zah
我一直以来都在“错误”的道路上。而当我说“一直以来”,我是指自从1995年开始写JavaScript以来。 - Dave Land
3个回答

76

根据道格拉斯·克罗克福德的样式约定指南:(搜索“立即调用”)

当一个函数需要立即调用时,整个调用表达式应该用括号括起来,以便清楚地表明产生的值是函数的结果而不是函数本身。

所以,基本上他认为这样可以更清晰地区分函数值和函数的值。因此,这是一种风格上的问题,而不是代码本身的实质性差异。

更新参考资料,旧PPT已不存在


1
我很高兴读到这篇文章。我刚刚读完了《JavaScript语言精粹》这本书,而我的想法一直是将函数调用结果赋值给变量是非常糟糕的语法,因为你必须查看首尾行才能理解发生了什么。他在书中没有使用包裹的圆括号,但我确切地知道他为什么推荐使用它们。 - Skilldrick
2
@altCognito,你能提供一份PPT的新链接吗? - th1rdey3
1
我在网上搜索了,但仍然找不到那个PPT的副本。 - Forethinker
1
我找不到原始的PPT,但我能够在他的JavaScript约定指南中找到相同的要点。 - cgp
互联网档案馆有它吗? - John Greene

2

立即调用的匿名函数需要用括号包裹,因为:

  1. 它们是函数表达式,如果省略括号,则会被解释为函数声明,这是语法错误。

  2. 函数表达式不能以 function 关键字开头。

  3. 将函数表达式赋值给变量时,不会返回函数本身,而是返回函数的返回值。因此,括号会计算其中的内容并产生一个值。当函数被执行时,末尾的括号 ..}() 会导致函数立即执行。


Dathan,你回答了一个不同的问题。你是正确的,括号有时在语法上是必要的,这样解析器才能区分函数表达式和函数声明。但我的问题是关于调用括号的放置。你的第三点是不准确的;在那种情况下,括号是不必要的。 - Bobby Eickhoff
我在回答你的第一个例子,其中立即调用的匿名函数没有分配给变量,因此括号在语法上对前两个原因是必要的。第三个原因只是重申了你所说的:“开括号提供了一个明确的指示,即被赋值的值不是函数本身,而是函数被调用后的结果。”但我想可能不够清楚。 - Dathan

-4

或者,使用:

void function () {
...
} ()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接