自动执行匿名 JavaScript 函数的括号位置?

最近,我将 Json2.js的当前版本与我在项目中使用的版本进行了比较,发现函数表达式的创建和自我执行方式有所不同。

用于在括号中包装匿名函数然后执行它的代码,

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

但现在它将自动执行的函数包装在括号中。

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

CMS 在 解释 JavaScript 封装的匿名函数语法的公认答案中有一条评论,“ (function(){})();(function(){}());都是有效的。”

我想知道有什么区别吗?前者是否通过留下一个全局的匿名函数来占用内存?括号应该放在哪里?

15016 次浏览

They're virtually the same.

The first wraps parentheses around a function to make it a valid expression and invokes it. The result of the expression is undefined.

The second executes the function and the parentheses around the automatic invocation make it a valid expression. It also evaluates to undefined.

I don't think there's a "right" way of doing it, since the result of the expression is the same.

> function(){}()
SyntaxError: Unexpected token (
> (function(){})()
undefined
> (function(){return 'foo'})()
"foo"
> (function(){ return 'foo'}())
"foo"

In that case it doesn't matter. You are invoking an expression that resolves to a function in the first definition, and defining and immediately invoking a function in the second example. They're similar because the function expression in the first example is just the function definition.

There are other more obviously useful cases for invoking expressions that resolve to functions:

(foo || bar)()

There isn't any difference beyond the syntax.

Regarding your concerns about the second method of doing it:

Consider:

(function namedfunc () { ... }())

namedfunc will still not be in the global scope even though you provided the name. The same goes for anonymous functions. The only way to get it in that scope would be to assign it to a variable inside the parens.

((namedfunc = function namedfunc () { ... })())

The outer parens are unnecessary:

(namedfunc = function namedfunc () { ... })()

But you didn't want that global declaration anyways, did you?

So it it boils down to:

(function namedfunc () { ... })()

And you can reduce it even further: the name is unnecessary since it will never be used (unless your function is recursive.. and even then you could use arguments.callee)

(function () { ... })()

That's the way I think about it (may be incorrect, I haven't read the ECMAScript specification yet). Hope it helps.

The difference just exist because Douglas Crockford doesn't like the first style for IIFEs! (seriuosly) As you can see in this video!!.

The only reason for the existence of the extra wrapping () {in both styles} is to help make that section of code Function Expression, because Function Declaration cannot be immediately called. Some scripts / minify-ers just use +, !, - & ~ instead of too parentheses. Like this:

+function() {
var foo = 'bar';
}();


!function() {
var foo = 'bar';
}();


-function() {
var foo = 'bar';
}();


~function() {
var foo = 'bar';
}();

And all these are exactly the same as your alternatives. Choosing among these cases is completely on your own & makes no difference. { The ones with () produce 1 Byte larger File ;-) }