功能上的额外括号

时间:2012-08-03 12:39:06

标签: javascript closures

  

可能重复:
  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

我遇到了与此类似的标记:

var something = (function(){
    //do stuff
    return stuff;
})()
document.ondblclick = function(e) { alert(something(e)) };

我不理解(变量中的开头)()和结束something。 你能解释一下像这样写的差异吗?

var something = function(){
    //do stuff
    return stuff;
};

谢谢!

5 个答案:

答案 0 :(得分:5)

(function(){ ... })(anonymous) function expression,您可以例如将该值赋给变量。

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

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

答案 1 :(得分:5)

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

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

答案 2 :(得分:4)

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

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

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的值。

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

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的值。

进一步阅读关闭:Use Cases for JavaScript Closures

答案 3 :(得分:1)

同时查看JavaScript常见问题解答部分:Here are some pretty good explanations and examples

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

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

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控制。

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

答案 4 :(得分:1)

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

var something = (function(){
    //do stuff
    return stuff;
})()

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

var something = function(){
    //do stuff
    return stuff;
};

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