我知道封闭是什么,但我仍然不明白为什么(或何时)你会使用它们

时间:2010-08-09 16:32:52

标签: javascript programming-languages closures

我对闭包的理解是它们本质上是一个函数,它使用一个你认为超出范围的变量。我想这是我前几天看到的一个例子:

function closureMaker(somearg)
{
    var local_value = 7;
    function funcToReturn(arg1, arg2)
    {
        return local_value + somearg + arg1 + arg2;
    }
    return funcToReturn;
}
var myClosure = closureMaker(6);  //make the closure
myClosure(2, 3);                  //using it

现在闭包有local_value甚至是原始的arg,somearg。但我不明白为什么这些都有帮助。使用'free'变量local_value有什么意义,甚至更不为我所知,为什么你会在闭包函数中使用closureMaking函数的参数?

我对如何在javascript中使用它更感兴趣,这是否对AJAX请求和对象使用了很多?

我得到了什么。我需要原因。

7 个答案:

答案 0 :(得分:6)

闭包最实用和最广泛使用的一种方法是实现private or privileged members,例如:

function Test (param) {
  var secret = 3;
  function privateMethod() {
    //...
  }
  this.publicMember = param;
  this.privilegedMember = function () {
    return secret * param;
  };
}

var foo = new Test(10);
foo.privilegedMember(); // 30
foo.secret; // undefined

module pattern也是一个很好的例子,它可以使用相同的原理,例如:

var myModule = (function () { 
  var obj = {}, privateVariable = 1; 

  function privateMethod() { 
    // ... 
  } 

  obj.publicProperty = 1; 
  obj.publicMethod = function () { 
    // private members available here... 
  }; 

  return obj; 
}());

答案 1 :(得分:4)

常见的磨合是在for循环中,您需要提醒计数器的编号。

function addLinks () {
    for(var i = 0; i < 5; ++i) {
        var link = document.createElement('a');
        link.appendChild(document.createTextNode('Link ' + i));
        link.i = i;
        link.onclick = function() { alert( i ) };
        document.body.appendChild(link);
    }
}

addLinks();

当您点击这些链接时,它会提醒5,因为循环已经完成且i等于5。我们没有在执行for循环时“保存”i的状态。

我们可以关闭“保存”该状态:

function addLinks () {
    for(var i = 0; i < 5; ++i) {
        var link = document.createElement('a');
        link.appendChild(document.createTextNode('Link ' + i));
        link.i = i;
        link.onclick = (function(i) { return function() {  alert(i ) } })(i);
        document.body.appendChild(link);
    }
}

addLinks();

i绑定到循环中每个增量内调用的自执行匿名函数。通过这种方式,状态得以保存,我们在警报时获得正确的#。

答案 2 :(得分:4)

您正在查看的示例是试图向您展示闭包的工作原理。我认为闭包是你可以传递的一小段代码。巧妙的是,闭包中的(自由)变量基于当前的词法范围进行绑定。这就是local_value保留值7的原因,因为这是创建闭包时local_value的值。

Javascript通过closures * 实现anonymous functions,但请记住,从技术上讲,这是两个独立的概念。

在Javascript的上下文中,当你想要处理异步发生的事情时,闭包(作为匿名函数实现)非常有用;一个很好的例子就像你说的那样,AJAX请求你无法预测何时从服务器获得响应。在这种情况下,您有一个名为 callback 的匿名函数,您最初定义并在进行AJAX调用时传入。调用成功完成后,将调用您的回调来处理结果。闭包会产生更清晰的代码,因为您可以将行为和逻辑打包在其中。它还可以帮助您抽象我们的行为和单独的问题。

匿名函数/闭包的另一个用途是用于事件处理。当事件发生时,您的事件处理程序将被调用。

就像我之前提到的那样,你可以抽象出行为和逻辑并把它放在一个闭包中。但真正使得闭包如此强大的是 context 。您可以自定义闭包的行为,具体取决于它的创建环境。这使得您的函数非常通用,因为您在创建它时定义它的参数(这会影响它的行为),而不是在执行期间调用它(使用显式参数)。

这是一篇关于Javascript中的闭包的好文章。这很长,但内容丰富:

* 正如CMS所提到的,名为的函数将表现得像匿名函数,因为它们可以访问在同一个词法中定义的变量范围(或链上的任何东西)。这在内部函数中最为明显。但是如果你考虑一下,任何功能都会发生同样的情况;您可以访问已在全局范围中定义的变量(即全局变量)。

答案 3 :(得分:0)

这可能不是你想要的,但是关于Java的闭包(它们应该/可以如何实现)有一个很好的讨论,这也是关于你想要使用它们的一些例子

http://www.youtube.com/watch?v=0zVizaCOhME

答案 4 :(得分:0)

闭包是一种简单的方法,可以使函数依赖于参数。或者换句话说,创建一个系列函数的特定实例(如果不清楚则读取),具体取决于某些运行时值。

Javascript允许您将函数作为一等成员传递;例如,您可以通过直接引用它来传递一个确定如何组合两个整数的函数。

然而,更进一步,闭包允许您创建函数的“自定义”版本,其确切行为取决于某些运行时变量(但是否则符合框架)。

例如,这是一个允许添加curried的函数:

function getAddNFunction(n)
{
    function inner(operand)
    {
        return n + operand;
    }
    return inner;
}

现在,如果你调用getAddNFunction(7),你会得到一个为参数添加7的函数。如果你调用getAddNFunction(42.5),你会得到一个为参数添加42.5的函数。

希望这个简单的例子澄清了闭包的好处;它们允许您在创建时在函数中嵌入参数,而不是必须在执行时传入它们(毕竟,调用getAddNFunction(9)(2)与调用{{1}完全相同除了可以在非常不同的时间提供两个参数这一事实外。)

因此,例如,您可能希望返回某种相对于某个根元素的复杂XML解析函数;一个闭包允许你将根元素定义嵌入到函数本身中,而不是依赖于调用者在想要执行函数时有权访问它。

答案 5 :(得分:0)

如果您来自OO世界,那么闭包允许您为对象创建基本上私有的成员变量和方法:

function Constructor(...) {
  var privateVar = value;
  function privateFunc() {
  }
  this.publicFunc = function() {
  // public func has access to privateVar and privateFunc, but code outside Constructor does not
  }
}

Douglas Crockford and javascript goodness

答案 6 :(得分:0)

除了上面的闭包有助于隐藏一些实现细节。

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();

alert(Counter.value()); /* Alerts 0 */
Counter.increment();
Counter.increment();
alert(Counter.value()); /* Alerts 2 */
Counter.decrement();
alert(Counter.value()); /* Alerts 1 */

One more good article

Read this article on module pattern in javascript which heavily uses closures.