为什么这个匿名函数调用中缺少括号?

15

我正在阅读这本书,它有这个代码示例

function getFunction() {
    var result = [];
    for (var i = 0; i < 10; i++) {
        result[i] = function(num) {
            return function() {
                console.log("this is " + num);
            }
        }(i);
    };

    return result;
}

它正在正常工作,但是为什么这里的匿名函数没有像这样用括号括起来 (function(...))(i); ? 在哪些情况下可以省略匿名函数的括号?


请注意,使函数成为表达式的方法还有其他方式。例如:!function(){}()0/function(){}() 或者我最喜欢的 -function(){}() - slebetman
还可以在其他地方查看为什么括号是必需的 - Bergi
4个回答

18

由于函数声明和函数表达式的语法相同,JS通过函数周围的代码来区分使用哪种方法。

要避免它成为函数声明,您需要在表达式中使用它。用括号将其包裹起来就可以实现,但在其前面加上=也可以(以及其他一些运算符)。由于这里有一个=,所以括号是不必要的。


8

由于它作为赋值运算符=的第二个操作数使用,因此JS引擎可以将其视为函数表达式。

但是当您单独定义匿名函数时,情况并非如此:在这种情况下,您需要帮助引擎将其视为表达式,而不是语句。


4

常规的函数声明看起来像这样:

function FuncName() { doSomething(); }

然后您可以像这样调用此函数:
FuncName();

匿名函数非常相似:

var FuncName = function YouCanEvenPutANameHereAndItWillBeIgnored() { doSomething(); }

如果常规函数和匿名函数的语法相同,那么JS如何区分它们?它从上下文中推断你的意思。这就是为什么这个立即调用的函数表达式不起作用的原因:

function(s) { console.log(s); } ('abc');

JS解析器从左边开始读取。该行以function开头,所以JS猜测它是一个常规函数声明,并期望它以}结束。不过,在函数后面有('abc'),因此JS会报错。

要修复它,您必须欺骗JS将该函数解析为匿名函数。为此,您必须使其成为表达式的一部分。最流行的方法是这样:

(function(s) { console.log(s); }) ('abc');

有其他方式,虽然它们不太易读,但它们也是有效的。
( function(s) { console.log(s); } ('abc') );
+function(s) { console.log(s); } ('abc');
-function(s) { console.log(s); } ('abc');
1 * function(s) { console.log(s); } ('abc');

在您的情况下,该函数已经是表达式的一部分,因此无需添加括号。

1
因为函数没有名称,所以以“function”开头的那一行是一个解析错误。function log(s) { console.log(s); } (function(s) { console.log(s); } ('abc'))声明了一个名为log的函数,并记录了 abc。但是如果将其括在括号中,则会执行而不是声明。另外,“!”经常用于使代码解析为表达式,它与自动分号插入的交互效果很好。 - Neil

2

这些是立即调用的函数表达式(IIFE)。它们可以在任何需要表达式的地方使用。例如,在等号右侧,比较运算符的任一侧甚至作为另一个函数的参数。如果它们被用在不需要表达式的地方,则需要括号。例如下面的例子:

var a=1;
(function(b){
  a=b;
})(2);
console.log(a);

这个输出的结果是2。

在任何需要表达式的地方,以下三种方式是等效的:

function(a){....}(b);

(function(a){....})(b);

(function(a){....}(b));

然而,括号被认为是最佳实践,因为它们“提示”这是一个立即调用的函数,而不必向下滚动到函数的末尾。


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