10

可能重复:
JavaScript 对象/函数/类声明周围的括号是什么意思?
这个“(function(){});”,括号内的函数,在javascript中是什么意思?
一个Javascript函数

我遇到了类似这样的标记:

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

我不明白变量中的打开(和关闭。你能解释一下这样写的区别吗?)()something

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

谢谢!

4

5 回答 5

5

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

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

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

于 2012-08-03T12:49:51.010 回答
5

如果您将多余的括号排除在外,可能会更容易理解,因为它们没有任何用途:

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
于 2012-08-03T12:57:36.653 回答
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 的值。

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

于 2012-08-03T12:45:43.463 回答
1

也请查看 JavaScript FAQ 部分:这里有一些很好的解释和示例

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

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

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 处理。但是在这种情况下,该函数返回了另一个函数,该函数具有指向这些参数的链接(它需要它们),因此只要它们aClosure存在,它们就不会被 GC 处理。

正如我在评论中所说。谷歌关闭,练习一下,你会明白的......他们真的很强大

于 2012-08-03T12:51:24.987 回答
1

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

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

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

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

这段代码执行后,something 一个返回的函数stuff。返回内容的函数从未执行过。

于 2012-08-03T13:03:24.790 回答