不完全理解这个闭包是如何工作的
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 变量成为全局变量来实现类似的功能,但这种模式的好处在于它限制了您的全局变量,并且还为变量提供了隐私。来自立即调用函数之外的任何调用都无法访问计数。
我摘录自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 变量成为全局变量来实现类似的功能,但这种模式的好处在于它限制了您的全局变量,并且还为变量提供了隐私。来自立即调用函数之外的任何调用都无法访问计数。