如何声明自调用函数?

8
我见过像这样用Javascript编写的自调用函数:

(function () {
    // foo!
})();

但我也看到它们被写成这样:
(function () {
    // bar!
}());

从句法上来说,它们完全做同样的事情。实际上,我的个人习惯是第一种格式,但是这两种格式之间有什么区别我应该注意吗?比如浏览器问题或其他问题?
举个很微不足道的例子,如果第二种格式能够可靠地工作,那么类似这样的东西也应该是可能的:
function () {
    // shut the front door! saved two characters right there!
}();

这会严重影响可读性。

1
我认为这个主题已经被讨论得足够多了,在 Stack Overflow 上进行一点搜索应该会给你正确的答案。 - Rafael Herscovici
可能是重复问题:https://dev59.com/-FrUa4cB1Zd3GeqPl6Vl - Some Guy
我总是使用你的第一种构造方式,它从未出现过问题。我相信第二种方式也会起作用。但第三种方式并不总是有效,因为在某些情况下解释器需要知道表达式和函数定义之间的区别。 - jfriend00
可能是[自动执行匿名JavaScript函数的括号位置?](https://dev59.com/BXA75IYBdhLWcg3wRW2c)的重复问题。 - scrappedcola
@Dementic ~ 对不起,我的确进行了搜索,但我猜可能是术语不同导致没有搜索结果。 - Richard Neil Ilagan
6个回答

4

首先:

就像您所想的那样,自调用匿名函数的前两个版本之间没有任何区别。没有浏览器的问题,只是个人喜好(顺便说一下,Douglas Crockford称后者为“狗球”)。

其次:

function() {
}()

设计上,这段代码不会运行,因为它创建了一个“function statement/declaration”。你需要创建一个能够立即调用自身的“function expression”。要创建一个函数表达式,你可以采取多种方式。将整个语句放入括号中是一种方法,但你也可以这样写:

!function() {
}()

或者

+function() {
}

所有这些操作符都会生成一个表达式。

@Amaan — 因为在那个上下文中它是一个函数表达式,而不是函数声明。函数声明在那里是不允许的。 - Quentin
据我所知,函数语句只是函数声明的不同措辞。 - Andre Meinhold
函数声明不能存在于括号内。更多细节请参见此处:http://benalman.com/news/2010/11/immediately-invoked-function-expression/ - Ben McCormick
@Andre ~ 我甚至没有看到函数声明语法出现。真可惜,真可惜。 - Richard Neil Ilagan
@Amaan 在这种情况下,该函数是一个_命名函数表达式_。请参阅http://kangax.github.com/nfe/。 - Cameron Martin

1

前两个是相同的,但如果我没记错的话,其中一个被jsLint所偏爱(我想应该是第二个)。

第三个在大多数解释器中会引发语法错误,但还有其他变体:

!function() {
    alert('I’m executing myself!');
}();

var noname = function() {
    alert(noname); // undefined!
}();

你可以用+-替换!(但这样做不会让Crockford感到满意)


今天我了解到 !+- 可以强制执行语句。虽然这些对我来说并没有什么用,但在代码压缩和混淆方面可能会有所帮助。 - Richard Neil Ilagan

0

从实用角度来看,JSLint 会抱怨第一种格式并更喜欢第二种格式。除此之外,这真的是个人偏好,保持一致性很重要。

第三种格式将导致 SyntaxError,因此您不能使用它。那是因为您正在创建一个函数声明,而不是函数表达式。当您使用立即函数模式时,调用的是函数表达式。


0

Crockford建议使用(function () {...}())

这只是一种风格上的选择,但为了整个社区的利益,我们应该在惯例上达成一致,而且(冒着引发争端的风险)使用Crockford的方式又有什么不好呢?


0
此外,请记住 (function () { }()); 可能会带来混淆。因为在一个很长的函数中,有些人可能会看到两个闭合括号,但只有一个被打开。

这就是为什么我会问,即使事情看起来非常琐碎。在阅读了@ethagnawl的答案之后,我又读了你的答案。这就是开发环境吧,我想。 - Richard Neil Ilagan

0

这主要是一个约定问题。

(function () {}()); <- 执行前少了一个堆栈帧(也许)

(function () {})(); <- 在括号外执行,因此在执行前有一个微小的帧,尽管我不喜欢这种风格,我认为它在视觉上是不连贯的。

function () {}(); <- 我认为这只是一种不好的做法,它并不立即明显地表明这是一个IIFE,这主要是由于约定而造成的,但这也存在一个问题,如果在表达式之前忘记分号,则在某些情况下会静默地将变量赋值为undefined。

例如:

var x = 0,
    y = 1,
    z = 3,

function () {
    alert("Z is now undefined, instead of throwing a syntax error.");
}();

正如Andre Meinhold所提到的,这不是表达式位置。


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