这两个JavaScript声明有什么区别?

10

其中一个括号 "()" 在里面,而另一个在外面。它们如下所示:

var a = (function() {
    return {
        bla: function() {
            console.log('a');
        }
    };
} () );

var b = (function() {
    return {
        bla: function() {
            console.log('b');
        }
    };
}) ();

a.bla();
b.bla();

第二种模式通常被称为模块模式,我不是JS高手,很想看到正确的答案。 - Kumar
可能是自动执行匿名JavaScript函数的括号位置?的重复问题。 - Bergi
5个回答

9

没有区别。

这些[不必要的]括号只是放置位置不同。由于函数声明所在的位置,函数声明本身就已经是一个表达式。如果声明在一个语句上下文中(具有讽刺意味的是,这样会将其转换回表达式上下文),则括号会产生差异,但仍然会导致等效的代码,而它并不是这种情况。


在类似的场景中,括号的常见用法是自执行函数。在这种情况下,需要使用括号。

function x () { alert("hi!") } ()

被解析为

function x () { alert("hi!") }; ()

当它作为语句出现时,或者作为“块的顶级元素”出现时,它会被解析为“FunctionDeclaration”。因此,通常使用以下形式:

(function () { alert("hi!") })()

这是因为function ...不再是语句,而是表达式(解析为"FunctionExpression"),并且表达式可以继续,因此与上一个情况不同,不会发生自动分号插入。还要注意函数名可以省略。
然而,在本文中,function ...出现在=的右侧(在"AssignmentExpression"中),因此它已经处于表达式上下文中(解析为"FunctionExpression"),因此不需要额外的括号。
所有这些形式都是相同的,但我更喜欢第二种形式(为了在我的代码中保持一致)。
a = function () {} ()
b = (function () {}) ()
c = (function () {} ())

愉快的编码。


你能否解释一下什么是“语句上下文”? - Kumar
1
@Kumar请参阅ECMAScript第5版的第12节以获取语法规则。我已经添加了“正确”的术语,用于创建函数对象的两种不同语法结构。请注意,ExpressionStatement 不能{function开头,这会强制将作为块的“顶级元素”出现的函数定义视为FunctionDeclaration。 - user166390

2
没有实质性的区别。两者的工作方式相同。如果您想通过 JSLint,则需要使用第一种模式,其中调用括号位于另一组括号内部。如果不这样做,您将收到以下错误提示:

将调用移入包含该函数的括号中。

此外,请注意第一组括号不是必需的。没有它们也可以工作,但会再次导致 JSLint 失败:

将立即函数调用包装在括号中,以帮助读者理解该表达式是函数的结果,而不是函数本身。


一些相关问题:

JSLint 错误:"将调用移入包含该函数的括号中"

JSLint 错误的解决方案


你有没有找到为什么在 JSLint 中做出这个选择的原因?它似乎是武断的... - Guffa
1
@Guffa - 我认为这是随意的。只是Crockford决定他喜欢什么。就我个人而言,我倾向于遵循这两个JSLint规则,但我非常确定这在这种情况下没有任何影响。 - James Allardice
1
我认为外层括号是为了可读性而存在的。它们清楚地表明,关闭的 () 不是任何不熟悉 JS 更复杂特性的其他开发人员的打字错误,以便将来进行编辑。 在我看来,对于简写 if 语句也适用,x == 1 ? 'foo' : y == 2 ? 'foobar' : 'bar'(x == 1 ? 'foo' : (y == 2 ? 'foobar' : 'bar')) 更难阅读,更容易出错。后者更容易在以后进行编辑... - Elias Van Ootegem
1
我不喜欢(或使用)JSLint,但是因为指出这个...怪癖而点赞。 - user166390

1

实际上没有实质性的区别,只是一个微小的差别,即您如何使Javascript引擎将函数视为值。

使用( function(){} () );会导致函数成为值,因为语句不能以括号开头。而使用( function(){} ) ();则使用括号首先将函数作为值进行评估,然后调用它。


在这两种情况下,function(){}首先被评估为一个函数对象。括号会强制它成为一个表达式...但它已经是了。 - user166390
@pst:是的,在这种情况下它已经是一个表达式了,但是括号在这种方式下的常见用法是将其变成一个表达式。这就是为什么即使在赋值时不需要它们,括号仍然存在的原因。 - Guffa
非常好; 我确实更喜欢[内部]圆括号形式以保持一致性。 - user166390

0

我认为这是相同的差异:

var myObj = {bla:'blabla'}; 
var a = (myObj);
var b = myObj;

...没有区别 :)


0

结尾的括号意味着:当一个函数需要立即调用时,整个调用表达式应该被包裹在括号中,以便清楚地表明产生的值是函数的结果而不是函数本身。(摘自这里

因此,如果使用{}(),函数将立即执行,并将变量赋值为函数的结果。

然后,如果使用({})(),如果在()之间有一个函数,则该函数将被执行,并将其值分配给变量。

在我看来,如果它们包含相同的函数,则它们是相同的东西。


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