关于javascript:功能上的额外括号

Extra parentheses on function

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
What do parentheses surrounding a JavaScript object/function/class declaration mean?
What does this “(function(){});”, a function inside brackets, mean in javascript?
A Javascript function

我遇到类似这样的标记:

1
2
3
4
5
var something = (function(){
    //do stuff
    return stuff;
})()
document.ondblclick = function(e) { alert(something(e)) };

我不明白something变量中的开头(和关闭)()
你能解释一下写这样的差异吗?

1
2
3
4
var something = function(){
    //do stuff
    return stuff;
};

谢谢!


如果你把冗余的parens遗漏掉,可能会更容易理解,因为它们没有用处:

1
2
3
4
5
6
7
8
9
10
11
12
13
var something = function() {
    return 3;
} // <-- a function.
(); // now invoke it and the result is 3 (because the return value is 3) assigned to variable called something

console.log(something) //3 because the function returned 3

var something = function() {
    return 3;
}; // a function is assigned to a variable called something

console.log(something) //logs the function body because it was assigned to a function
console.log(something()) //invoke the function assigned to something, resulting in 3 being logged to the console because that's what the function returns


(function(){ ... })是(匿名)函数表达式,您可以例如将该值赋给变量。

它后面的括号将立即执行函数表达式,从而产生函数的返回值(在这里:stuff)。该构造称为IIFE。

stuff是一个函数时(我假设,因为你稍后调用something),这称为闭包 - 返回的函数(stuff,分配给something)仍然可以访问执行中的变量匿名函数的上下文。


关于它的作用,请阅读所有评论和其他答案。他们是绝对正确的。

你为什么要用它?使用闭包时,您经常会发现这种模式。以下代码片段的目的是向10个不同的DOM元素添加一个事件处理程序,每个元素应该警告它的ID属性(例如"你点击了3")。您应该知道,如果这是您的实际意图,那么有一种更简单的方法可以做到这一点,但出于学术原因,让我们坚持这个实现。

1
2
3
4
5
6
7
8
9
10
var unorderedList = $("ul" );
for (var i = 0; i < 10; i++) {
    $("<li />", {
        id: i,
        text:"Link" + i,
        click: function() {
            console.log("You've clicked" + i);
        }
    }).appendTo( unorderedList );
}

上述代码的输出可能不是您首先预期的。每个点击处理程序的结果都是"你点击了9",因为触发事件处理程序时i的值是"9"。开发人员真正想要的是在定义事件处理程序的时间点显示i的值。

为了解决上述错误,我们可以引入一个闭包。

1
2
3
4
5
6
7
8
9
10
11
12
13
var unorderedList = $("ul" ), i;

for (i = 0; i < 10; i++) {
    $("<li />", {
        id: i,
        text:"Link" + i,
        click: function(index) {
            return function() {
                console.log("You've clicked" + index);
            }
        }(i)
    }).appendTo( unorderedList );
}

您可以从jsFiddle执行和修改上面的代码。

修复上述代码的一种方法是利用自执行匿名函数。这是一个奇特的术语,意味着我们将创建一个无名函数,然后立即调用它。该技术的价值在于变量的范围保持在函数内。因此,首先我们将在函数中包围事件处理程序内容,然后立即调用该函数并传入i的值。通过这样做,当事件处理程序被触发时,它将包含定义事件处理程序时存在的i的值。

关于闭包的进一步阅读:JavaScript闭包的用例


所有答案都很好,但我认为最简单的答案已被撇去:

1
2
3
4
var something = (function(){
    //do stuff
    return stuff;
})()

执行此代码后,something变为stuff。返回内容的函数在分配内容之前执行。

1
2
3
4
var something = function(){
    //do stuff
    return stuff;
};

执行此代码后,something是一个返回stuff的函数。返回东西的函数从未执行过。


请查看JavaScript常见问题解答部分:以下是一些非常好的解释和示例

好的,你为什么要用这个:

假设我的脚本正在运行,并且有一些事情(例如,我正在循环遍历节点列表)我可能稍后需要。这就是我选择做这样的事情的原因:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for(var i=0;i<nodesList.lenght;i++)
{
    if (nodesList[i].id==="theOneINeed")
    {
        aClosure = (function(node,indexInNodesList)//assign here
        {
            return function()
            {
                node.style.display = 'none';//usable after the parent function returns
                alert(indexInNodesList+ ' is now invisible');
            }
        })(nodesList[i],i);//pass the element and its index as arguments here
        break;
    }
}
i = 99999;
aClosure();//no arguments, but it'll still work, and say i was 15, even though I've just
//assigned another value to i, it'll alert '15 is now invisible'

这使我能做的是防止函数参数被垃圾收集。通常,在函数返回后,其所有var和参数都是GC'd。但在这种情况下,函数返回另一个函数,该函数具有到这些参数的链接(它需要它们),因此只要aClosure存在就不会GC。

正如我在评论中所说。谷歌关闭,练习一点,它会在你身上拂晓......它们真的非常强大