是否需要将函数返回称为闭包

时间:2013-05-16 12:05:06

标签: javascript closures

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

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

E.x。

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

在这种情况下,我可以将其称为闭包,因为它从外部函数的作用域访问'i'变量,或者我是否需要返回这样的函数

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

5 个答案:

答案 0 :(得分:4)

返回函数不会改变任何东西,重要的是创建它并调用它。这使得闭包,即从内部函数到创建它的作用域的链接(在实践中,您可以将其视为指针。例如,它具有阻止外部作用域的相同效果)

答案 1 :(得分:4)

一个闭包只是一个保持其词汇环境的功能,并且在它自身死亡之前不会放过它。

将封口想象成Uncle Scrooge:

enter image description here

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

同样,关闭也是一个吝啬鬼。在它自行消失之前,它不会放弃它的变量。

例如:

function getCounter() {
    var count = 0;

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

var counter = getCounter();

看到该函数countergetCounter函数返回的那个?这个功能是一个守财奴。即使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)为全局counter变量指定了新的counter函数。因此,内部counter函数将setCounter的范围转义为闭包。

实际上在JavaScript中,每个函数都是一个闭包。但是,在我们处理逃避父函数范围的函数之前我们才意识到这一点即使在调用父函数结束后仍保留一些属于父函数的变量。

有关详细信息,请阅读以下答案:https://stackoverflow.com/a/12931785/783743

答案 2 :(得分:1)

通过definition of closure,从函数到其包含范围的链接就足够了。所以基本上创建函数使它成为一个闭包,因为这是在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"

答案 3 :(得分: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

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

答案 4 :(得分:0)

以下关闭的解释集合。对我来说,“老虎书”中最让我满意的是......隐喻的也很有帮助,但只有在遇到这个之后......

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

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

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

c)tiger book:堆上(而不是堆栈)的数据结构,包含函数指针(MC)和环境指针(EP),代表函数变量;

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

e)google i / o video:类似于一个类的实例,其中数据(实例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时采用,并且变得普遍。