我正在尽最大努力理解JavaScript闭包。
通过返回一个内部函数,它可以访问直接父函数中定义的任何变量。
这对我有什么用?也许我还没完全搞清楚。我在网上看到的大多数示例都没有提供任何真实的代码,只是一些模糊的示例。
有人能告诉我一个闭包的真实用法吗?
比如这个吗?
var warnUser = function (msg) {
var calledCount = 0;
return function() {
calledCount++;
alert(msg + '\nYou have been warned ' + calledCount + ' times.');
};
};
var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();
假设,你想统计用户在网页上点击按钮的次数。
为此,您将在按钮的onclick事件上触发一个函数来更新变量的计数
<button onclick="updateClickCount()">click me</button>
现在有很多方法,比如:
你可以使用一个全局变量和一个函数来增加计数器:
Var计数器= 0;
函数updatecickcount () {
+ +计数器;
//用counter做一些事情
}
但是,问题在于页面上的任何脚本都可以更改计数器,而不需要调用updatecickcount()。
现在,你可能在考虑在函数内部声明变量:
函数updatecickcount () {
Var计数器= 0;
+ +计数器;
//用counter做一些事情
}
但是,嘿!每次调用updateClickCount()函数时,计数器再次被设置为1。
Thinking about nested functions?
Nested functions have access to the scope "above" them.
In this example, the inner function updateClickCount() has access to the counter variable in the parent function countWrapper():
function countWrapper() {
var counter = 0;
function updateClickCount() {
++counter;
// Do something with counter
}
updateClickCount();
return counter;
}
This could have solved the counter dilemma, if you could reach the updateClickCount() function from the outside and you also need to find a way to execute counter = 0 only once not everytime.
Closure to the rescue! (self-invoking function):
var updateClickCount = (function(){
var counter = 0;
return function(){
++counter;
// Do something with counter
}
})();
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
This way updateClickCount becomes a function. The "wonderful" part is that it can access the counter in the parent scope.
This is called a JavaScript closure. It makes it possible for a function to have "private" variables.
The counter is protected by the scope of the anonymous function, and can only be changed using the updateClickCount() function!
一个关于闭包的更生动的例子
< >脚本
var updatecickcount =(函数(){
Var计数器= 0;
返回函数(){
+ +计数器;
. getelementbyid(“spnCount”)。innerHTML =计数器;
}
})();
> < /脚本
< html >
<按钮onclick = " updateClickCount ()“>点击我> < /按钮
<div>你点击了
<span id="spnCount"> 0 </span> times!
< / div >
< / html >
参考:JavaScript闭包
闭包是一种创建生成器的有用方法,它是一个按需递增的序列:
var foobar = function(i){var count = count || i; return function(){return ++count;}}
巴兹 = 福巴(1);
console.log(“First Call: ” + baz());2
console.log(“第二次调用: ” + baz());3
区别总结如下:
Anonymous functions Defined functions
Cannot be used as a method Can be used as a method of an object
Exists only in the scope in which it is defined Exists within the object it is defined in
Can only be called in the scope in which it is defined Can be called at any point in the code
Can be reassigned a new value or deleted Cannot be deleted or changed
参考文献
AS3基础知识:功能
假设,你想统计用户在网页上点击按钮的次数。
为此,您将在按钮的onclick事件上触发一个函数来更新变量的计数
<button onclick="updateClickCount()">click me</button>
现在有很多方法,比如:
你可以使用一个全局变量和一个函数来增加计数器:
Var计数器= 0;
函数updatecickcount () {
+ +计数器;
//用counter做一些事情
}
但是,问题在于页面上的任何脚本都可以更改计数器,而不需要调用updatecickcount()。
现在,你可能在考虑在函数内部声明变量:
函数updatecickcount () {
Var计数器= 0;
+ +计数器;
//用counter做一些事情
}
但是,嘿!每次调用updateClickCount()函数时,计数器再次被设置为1。
Thinking about nested functions?
Nested functions have access to the scope "above" them.
In this example, the inner function updateClickCount() has access to the counter variable in the parent function countWrapper():
function countWrapper() {
var counter = 0;
function updateClickCount() {
++counter;
// Do something with counter
}
updateClickCount();
return counter;
}
This could have solved the counter dilemma, if you could reach the updateClickCount() function from the outside and you also need to find a way to execute counter = 0 only once not everytime.
Closure to the rescue! (self-invoking function):
var updateClickCount = (function(){
var counter = 0;
return function(){
++counter;
// Do something with counter
}
})();
The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression.
This way updateClickCount becomes a function. The "wonderful" part is that it can access the counter in the parent scope.
This is called a JavaScript closure. It makes it possible for a function to have "private" variables.
The counter is protected by the scope of the anonymous function, and can only be changed using the updateClickCount() function!
一个关于闭包的更生动的例子
< >脚本
var updatecickcount =(函数(){
Var计数器= 0;
返回函数(){
+ +计数器;
. getelementbyid(“spnCount”)。innerHTML =计数器;
}
})();
> < /脚本
< html >
<按钮onclick = " updateClickCount ()“>点击我> < /按钮
<div>你点击了
<span id="spnCount"> 0 </span> times!
< / div >
< / html >
参考:JavaScript闭包
这里我有一个闭包概念的简单例子,我们可以在我们的电子商务网站或其他许多网站上使用它。
我正在添加示例的JSFiddle链接。它包含一个由三种商品组成的小产品清单和一个购物车柜台。
JSFiddle
// Counter closure implemented function;
var CartCouter = function(){
var counter = 0;
function changeCounter(val){
counter += val
}
return {
increment: function(){
changeCounter(1);
},
decrement: function(){
changeCounter(-1);
},
value: function(){
return counter;
}
}
}
var cartCount = CartCouter();
function updateCart() {
document.getElementById('cartcount').innerHTML = cartCount.value();
}
var productlist = document.getElementsByClassName('item');
for(var i = 0; i< productlist.length; i++){
productlist[i].addEventListener('click', function(){
if(this.className.indexOf('selected') < 0){
this.className += " selected";
cartCount.increment();
updateCart();
}
else{
this.className = this.className.replace("selected", "");
cartCount.decrement();
updateCart();
}
})
}
.productslist{
padding: 10px;
}
ul li{
display: inline-block;
padding: 5px;
border: 1px solid #DDD;
text-align: center;
width: 25%;
cursor: pointer;
}
.selected{
background-color: #7CFEF0;
color: #333;
}
.cartdiv{
position: relative;
float: right;
padding: 5px;
box-sizing: border-box;
border: 1px solid #F1F1F1;
}
<div>
<h3>
Practical use of a JavaScript closure concept/private variable.
</h3>
<div class="cartdiv">
<span id="cartcount">0</span>
</div>
<div class="productslist">
<ul>
<li class="item">Product 1</li>
<li class="item">Product 2</li>
<li class="item">Product 3</li>
</ul>
</div>
</div>