不完全理解这个闭包是如何工作的

Not fully understanding how this closure works

我摘录自How do JavaScript closures work?

我很难理解闭包。

 <button type="button" id="bid">Click Me!</button> 
 <script>
 var element = document.getElementById('bid');
element.onclick = (function() {
    // init the count to 0
    var count = 0;

    return function(e) {  // <- This function becomes the onclick handler
        count++;          //    and will retain access to the above `count`

        if (count === 3) {
            // Do something every third time
            alert("Third time's the charm!");

            //Reset counter
            count = 0;
        }
    };
})();

如何在两次调用之间保存 'count' 值?每次调用 var = 0 时不应该重置它吗?

在回答你的问题之前,首先让我们讨论一下你的代码是如何工作的:

当你在另一个函数中定义一个函数时,它会创建一个 clouser.Inside 一个 clouser,内部函数可以访问外部函数 scope,我的意思是外部函数的变量参数 即使外部函数有returned。在您的代码中,外部函数是 immediately-invoked-function 。这意味着它在定义后立即被调用。当它 returns 时,内部函数被赋值给 onclick event.The click 函数可以访问,以及修改外部函数的变量 (in this case count which is defined in the outer function)即使它 returned。 我已经在你的code.Go里注释掉了,就清楚了

首先,立即调用的函数 (function(){...})() 将调用 immediately.It return 另一个 function.So 剩下的是一个 returned 函数,它将被分配到 onclik 处理程序。 所以,在 return 之后它将是

 var element = document.getElementById('bid');
    element.onclick =function(e) {  // <- This returned function has becomes the onclick handler
            count++;          //  it can access the outer function's count variable and modify it even if the outer function returns.

            if (count === 3) {
                // Do something every third time
                alert("Third time's the charm!");

                //Reset counter
                count = 0;  // it can also reset outer function's count variable to zero
            }
        };

How is 'count' value save between invokations? Should not it be reset every invokation by var = 0?

没错。如果你一次又一次地使用这段代码 并立即调用函数 每次计数都会从 zero.But 开始你可以看到美丽的如果你再次点击相同的按钮并且again.Even如果外部函数有returned,内部函数有访问其 variables.So 每次单击按钮时它们都会被修改

第一次点击按钮将打印 1,因此计数现在为 1。 第二次单击将再次修改它并打印 2 因此 on.Remember in clousers 内部函数可以访问外部函数的变量,即使外部函数 returns.So、内部函数没有任何计数 variable.It 是只是访问外部范围的 variable.So,第三次点击后它将再次分配给零。

 var element = document.getElementById('bid');
 var mydiv=document.getElementById('mydiv');

element.onclick = (function() {

// init the count to 0
var count = 0;

return function(e) {  // <- This function becomes the onclick handler
    count++; 
   mydiv.innerHTML+=count+'</br>';  //    and will retain access to the above `count`

    if (count === 3) {
        // Do something every third time
        mydiv.innerHTML +="Third time's the charm!</br>";

        //Reset counter
        count = 0;
    }
};
})();
 <button type="button" id="bid">keep clicking me </button> 
   <div id='mydiv'></div>

如果这样声明:

element.onclick = function() {
  var count = 0;
};

…你是对的,每次点击 count 都会被初始化为 0。

然而,它是这样声明的:

element.onclick = (function() {
  var count = 0;
  return function(e) {
    count++;
    ...
  };
})();

在这种情况下,onclick 处理程序已分配给函数的 result,即:

return function(e) {
  count++;
  ...
};

因此 count 在单击事件期间初始化为 0。

count 是代码中第一个函数的局部变量。由于第二个函数在该函数内,因此 count 可用。

如您所说,您的函数成为 onclick 处理程序,count 的赋值仅执行一次(当您的函数被创建并分配给点击处理程序时)。计数仍在函数的范围内,即函数保留一个引用并使用该引用。因此,它不会重置和递增。

外层函数,即括在圆括号中的函数,是 Immediately Invoked Function Expression 的一个例子。该函数同时被定义和调用,其 return 值被分配给 element.onclick.

既然我们可以直接将 element.onclick 设置为内部函数,那为什么还要费心呢?好吧,这与 JavaScript 范围规则有关。获得私有范围的唯一方法是将某些东西包装在函数中。这里,count 在外部函数中声明和初始化,有效地使其成为私有的。内部函数仍然可以访问和操作它。这就是术语闭包的全部含义——内部函数访问其封闭函数的变量。

外部函数只(立即)调用一次,因此 count 只被初始化为 0 一次。但是变量保留在内存中,不会被垃圾回收,因为 JavaScript 足够聪明,知道内部函数仍然需要访问它。

我喜欢的思考方式:

        var count = 0;//Belongs to the window 
        //object and I like to imagine a window object 
        //around it so that you can see 
        //that everything in javascript is enclosed!

        function() {count++};

我很确定您在理解上面的代码时没有任何困难。现在想象一下:

          var count = 0; //Belongs to the window 

          function x() {
              var count = 0;//Private to function x
              (function () {
                  count++;
                  alert(count);//What will this output?
              })();
          };

          x();
          alert(count);//And this?

你会看到第一个会输出1,第二个会输出0,为什么:因为它们是不同的变量。他们彼此无关。这就是人们喜欢在 javascript 中进行闭包的原因。如果你污染了全局名称 space 它可以被覆盖。

          var count = 0; //Belongs to the window 


          function x() {
              var count = 0;
              (function () {
                  count++;
                  alert(count);
              })();
          };

          x();
          alert(count);
          var count= 1;//Global count has now been overwritten
          alert(count);

您使用以下语法声明一个立即调用函数:

(function() {
    ...
})();

这 运行 仅在首次加载时出现一次。

返回的代码:

return function(e) {  // <- This function becomes the onclick handler
    count++;          //    and will retain access to the above `count`

    if (count === 3) {
        // Do something every third time
        alert("Third time's the charm!");

        //Reset counter
        count = 0;
    }
};

实际上成为点击处理程序。因此,每次单击时,只有返回函数中的代码是 运行。

由于 Javascript 中处理作用域的方式,内部函数可以访问外部函数中的变量。您可以通过使 count 变量成为全局变量来实现类似的功能,但这种模式的好处在于它限制了您的全局变量,并且还为变量提供了隐私。来自立即调用函数之外的任何调用都无法访问计数。