5

嘿,我在 youtube 上看到了这个视频http://www.youtube.com/watch?v=KRm-h6vcpxs

这基本上解释了 IIFE 和闭包。但我不明白的是我是否需要返回一个函数才能将其称为闭包。

前任

function a() {
    var i = 10;
    function b() {
       alert(i);
    }
}

在这种情况下,我可以称它为闭包,因为它正在从外部函数的范围访问“i”变量,还是我需要像这样返回函数

return function b(){alert(i);}
4

5 回答 5

6

闭包只是一个函数,它保存其词法环境,并且在它自己死亡之前不会让它离开。

把闭包想象成斯克罗吉叔叔:

在此处输入图像描述

斯克罗吉叔叔是个吝啬鬼。他永远不会放过他的钱。

同样,闭包也是吝啬鬼。它不会放弃它的变量,直到它自己死去。

例如:

function getCounter() {
    var count = 0;

    return function counter() {
        return ++count;
    };
}

var counter = getCounter();

看到那个功能了counter吗?函数返回的那个getCounter?该功能是一个吝啬鬼。count即使count变量属于getCounter函数调用并且该函数调用已经结束,它也不会释放变量。因此我们称之为counter闭包。

查看每个函数调用可能会创建变量。例如,对getCounter函数的调用会创建一个变量count。现在这个变量count通常在getCounter函数结束时消失。

但是,该counter函数(可以访问该count变量)不允许它在调用getCounter结束时死掉。这是因为counter功能需要count。因此,它只会count在它自己死后才允许死去。

现在要注意的真正有趣的事情是,counter它诞生于对getCounter. counter因此,当呼叫结束时甚至应该死getCounter- 但事实并非如此。即使在调用getCounter结束后它仍然存在,因为它超出了getCounter.

有很多方法counter可以逃脱getCounter. 最常见的方式是getCounter简单地返回counter。不过还有很多方法。例如:

var counter;

function setCounter() {
    var count = 0;

    counter = function counter() {
        return ++count;
    };
}

setCounter();

这里的姊妹函数getCounter(恰当地称为)为全局变量setCounter分配了一个新函数。因此内部函数逃脱了成为闭包的范围。countercountercountersetCounter

实际上,在 JavaScript 中,每个函数都是一个闭包。然而,直到我们处理那些脱离父函数范围保持属于父函数的某些变量即使在对父函数的调用结束后仍处于活动状态的函数时,我们才意识到这一点。

有关更多信息,请阅读此答案:https ://stackoverflow.com/a/12931785/783743

于 2013-05-16T13:56:40.627 回答
4

返回函数没有任何改变,重要的是创建并调用它。这使得闭包,即从内部函数到创建它的范围的链接(实际上,您可以将其视为指针。例如,它具有防止外部范围产生垃圾的相同效果) .

于 2013-05-16T12:07:01.667 回答
1

实际的闭包是变量的容器,因此函数可以使用创建它的范围内的变量。

返回函数是在与其创建位置不同的范围内使用它的一种方式,但更常见的用途是当它是来自异步调用的回调时。

任何情况下,一个函数使用来自一个作用域的变量,并且该函数在不同的作用域中使用,都使用闭包。例子:

var globalF; // a global variable

function x() { // just to have a local scope

  var local; // a local variable in the scope

  var f = function(){
    alert(local); // use the variable from the scope
  };

  globalF = f; // copy a reference to the function to the global variable

}

x(); // create the function
globalF(); // call the function

(这只是一个闭包的演示,让一个函数设置一个全局变量然后使用它并不是编写实际代码的好方法。)

于 2013-05-16T12:36:47.527 回答
1

下面是关闭的解释集合。对我来说,最让我满意的是《虎书》里的那本……比喻的也有很大帮助,但只有遇到了这本……

  • 闭包:在集合论中,闭包是一个(最小的)集合,一些运算产生的结果也属于这个集合,所以它有点像“某些运算下的最小封闭社会”。

a) sicp:在抽象代数中,如果对集合中的元素应用操作,则称该集合在操作下是闭合的,产生的元素又是集合中的一个元素。Lisp 社区也(不幸地)使用“闭包”这个词来描述一个完全不相关的概念:闭包是一种用于表示具有自由变量的过程的实现技术。

b) wiki:闭包是第一类函数,它在其定义环境中捕获自由变量的词法绑定。一旦它捕获了词法绑定,该函数就变成了一个闭包,因为它“关闭”了这些变量。”</p>

c) 老虎书:堆上(而不是栈上)的数据结构,包含函数指针(MC)和环境指针(EP),表示一个函数变量;

d) 在 lisp 上:一个函数和一组变量绑定的组合称为闭包;闭包是具有本地状态的函数;

e) google i/o video:类似于一个类的实例,其中数据(instance obj)封装了代码(vtab),而在闭包的情况下,代码(函数变量)封装了数据。

f) 封装的数据对函数变量是私有的,意味着闭包可以用于数据隐藏。

g) 非函数式编程语言中的闭包:C 中带有 cookie 的回调是类似的结构,也是 glib“闭包”:glib 闭包是封装类似事物的数据结构:信号回调指针,cookie 是私有数据,以及闭包的析构函数(因为 C 中没有 GC)。

h)老虎书:“高阶函数”和“嵌套函数范围”一起需要一个解决方案,即爸爸函数返回一个孩子函数,该函数引用其父亲范围内的变量,这意味着即使父亲也返回变量它的范围不能从堆栈中“弹出”......解决方案是在堆中分配闭包。

i)Greg Michaelson(10.15 美元):(在 lisp 实现中),闭包是一种识别自由变量和词法绑定变量之间关系的方法,当有必要(经常需要)返回一个函数值时,将自由变量冻结为来自定义范围。

j) 历史和词源:Peter J. Landin 在 1964 年将术语闭包定义为具有环境部分和控制部分,由他的 SECD 机器用于评估表达式。Joel Moses 认为 Landin 引入了闭包一词来指代一个 lambda 表达式,其开放绑定(自由变量)已被词法环境封闭(或绑定),从而导致封闭表达式或闭包。这种用法随后被 Sussman 和 Steele 在 1975 年定义 Scheme 时采用,并被广泛使用。

于 2013-11-02T15:06:58.970 回答
1

根据闭包的定义,从函数到其包含范围的链接就足够了。所以基本上创建函数使它成为一个闭包,因为这是在 JavaScript 中创建链接的地方:-)

然而,为了利用这个特性,我们确实从不同于它定义的范围调用函数——这就是术语“使用闭包”在实践中所指的。这可以是更低或更高的范围 - 并且函数不一定需要从定义它的函数中编辑。return

一些例子:

var x = null;

function a() {
    var i = "from a";
    function b() {
        alert(i); // reference to variable from a's scope
    }
    function c() {
        var i = "c";
        // use from lower scope
        b(); // "from a" - not "c"
    }
    c();

    // export by argument passing
    [0].forEach(b); // "from a";
    // export by assigning to variable in higher scope
    x = b;
    // export by returning
    return b;
}
var y = a();
x(); // "from a"
y(); // "from a"
于 2013-05-16T12:12:15.287 回答