我正在尽最大努力理解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();
我正在尝试学习闭包,我认为我创建的示例是一个实际的用例。您可以运行一个代码片段并在控制台中查看结果。
我们有两个不同的用户,他们拥有不同的数据。它们中的每一个都可以看到实际的状态并进行更新。
function createUserWarningData(user) {
const data = {
name: user,
numberOfWarnings: 0,
};
function addWarning() {
data.numberOfWarnings = data.numberOfWarnings + 1;
}
function getUserData() {
console.log(data);
return data;
}
return {
getUserData: getUserData,
addWarning: addWarning,
};
}
const user1 = createUserWarningData("Thomas");
const user2 = createUserWarningData("Alex");
//USER 1
user1.getUserData(); // Returning data user object
user1.addWarning(); // Add one warning to specific user
user1.getUserData(); // Returning data user object
//USER2
user2.getUserData(); // Returning data user object
user2.addWarning(); // Add one warning to specific user
user2.addWarning(); // Add one warning to specific user
user2.getUserData(); // Returning data user object
这里我有一个闭包概念的简单例子,我们可以在我们的电子商务网站或其他许多网站上使用它。
我正在添加示例的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>
解释JavaScript闭包的实际用法
当我们在另一个函数中创建一个函数时,我们是在创建一个闭包。闭包功能强大,因为它们能够读取和操作其外部函数的数据。无论何时调用函数,都会为该调用创建一个新的作用域。在函数内部声明的局部变量属于该作用域,并且只能从该函数访问它们。当函数完成执行时,作用域通常被销毁。
这类函数的一个简单例子是:
function buildName(name) {
const greeting = "Hello, " + name;
return greeting;
}
在上面的例子中,函数buildName()声明了一个局部变量greeting并返回它。每次函数调用都会创建一个新的作用域和一个新的局部变量。在函数执行完成后,我们无法再次引用该作用域,因此它被垃圾收集。
但如果我们有一个指向范围的链接呢?
让我们看看下一个函数:
函数buildName(name) {
const greeting = "Hello, " + name + " Welcome ";
const sayName = function() {
console.log(问候);
};
返回sayName;
}
const sayMyName = buildName("Mandeep");
sayMyName ();//你好,曼迪普
本例中的sayName()函数是一个闭包。sayName()函数有自己的局部作用域(变量welcome),也可以访问外部(封闭)函数的作用域。在本例中,是来自buildName()的greeting变量。
在执行buildName之后,在本例中不会销毁作用域。sayMyName()函数仍然可以访问它,因此它不会被垃圾收集。但是,除了闭包之外,没有其他从外部作用域访问数据的方法。闭包充当全局上下文和外部作用域之间的网关。
是的,这是一个有用闭包的好例子。对warnUser的调用在其作用域中创建calledCount变量,并返回一个匿名函数,该函数存储在warnForTamper变量中。因为仍然有一个使用calledCount变量的闭包,所以在函数退出时不会删除它,所以每次调用warnForTamper()都会增加作用域变量并提醒该值。
我在Stack Overflow上看到的最常见的问题是,有人想要“延迟”使用在每次循环中增加的变量,但因为变量是有作用域的,所以对变量的每次引用都是在循环结束后,导致变量的结束状态:
for (var i = 0; i < someVar.length; i++)
window.setTimeout(function () {
alert("Value of i was "+i+" when this timer was set" )
}, 10000);
这将导致每个警报都显示相同的i值,即循环结束时它增加到的值。解决方案是创建一个新的闭包,一个变量的独立作用域。这可以使用一个立即执行的匿名函数来完成,该函数接收变量并将其状态存储为参数:
for (var i = 0; i < someVar.length; i++)
(function (i) {
window.setTimeout(function () {
alert("Value of i was " + i + " when this timer was set")
}, 10000);
})(i);