我摘录自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重置每次调用吗?
答案 0 :(得分:1)
在回答您的问题之前,首先让我们讨论您的代码的工作原理:
当你在另一个函数中定义一个函数时,它会创建一个clouser.Inside一个clouser内部函数可以访问外部函数 scope ,我的意思是外部函数的 变量 和 参数 即使外部函数已返回 。在您的代码中,外部函数是immediately-invoked-function。这意味着它在定义后立即被调用。当它返回时,内部函数被分配给onclick事件。单击函数可以访问,并修改外部函数的变量(in this case
count
which is defined in the outer function)
,即使它返回。
我已经在你的代码中注释掉了。通过它,它会很清楚
首先,立即调用函数(function(){...})()
将立即调用。它返回另一个函数。所剩下的是一个返回的函数,它将被分配给onclik处理程序。
因此,返回后将是
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
}
};
如何在“调用”之间保存“计数”值?不应该重置 每次调用var = 0?
右。如果你一次又一次地使用这个代码 并立即调用函数 ,每次计数将从零开始。但是如果你 一次又一次地点击 相同的按钮。即使外部函数已经返回,内部函数也可以访问它的变量。所以每次单击按钮都会修改它们
首先点击按钮将打印1,因此计数现在为1。 第二次单击将再次修改它并将打印2依此类推。即使外部函数返回,clousers内部函数也可以访问外部函数的变量。因此,内部函数没有任何计数变量。它只是访问外部作用域的变量。因此,在第三次点击后,它将再次分配为零。</ p>
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>
答案 1 :(得分:0)
如果声明如下:
element.onclick = function() {
var count = 0;
};
...您确认每次点击都会将count
初始化为0。
但是,它的声明如下:
element.onclick = (function() {
var count = 0;
return function(e) {
count++;
...
};
})();
在这种情况下,onclick
处理程序已分配给函数的结果,即:
return function(e) {
count++;
...
};
因此,在点击事件期间count
count
是代码中第一个函数的本地函数。由于第二个函数在该函数内,因此count
可用。
答案 2 :(得分:0)
正如你所说,你的函数变成了onclick处理程序,count的赋值只执行一次(当你的函数被创建并分配给click处理程序时)。计数仍然在函数的范围内,即函数保留引用并使用该引用。因此,它不会重置和递增。
答案 3 :(得分:0)
外部函数,括在括号中的函数,是Immediately Invoked Function Expression的一个例子。该函数既被定义又被立即调用,其返回值是分配给element.onclick
的函数。
那么,为什么我们可以直接将element.onclick
设置为内部函数呢?那么,这与JavaScript范围规则有关。获取私有作用域的唯一方法是在函数中包装一些东西。这里,count
在外部函数中声明并初始化,实际上使其成为私有。内部函数仍然可以访问和操作它。这就是闭包一词的意思 - 一个内部函数访问其封闭函数的变量。
外部函数只被调用一次(立即),因此count
只被初始化为0一次。但是变量仍然存在于内存中并且不会被垃圾收集,因为JavaScript足够聪明,知道内部函数仍然需要访问它。
答案 4 :(得分:0)
我喜欢思考的方式:
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中制作闭包的原因。如果污染全局名称空间,则可以覆盖它。
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);
答案 5 :(得分:0)
使用以下语法声明一个立即调用的函数:
(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变量全局来完成类似的功能,但是这个模式的好处是它限制了你的全局变量,并且还提供了变量隐私。来自您立即调用函数外部的调用将无法访问计数。