我正在w3schools上阅读这个关于应用于“反困境”的Javascript闭包的例子:
https://www.w3schools.com/js/js_function_closures.asp
在实际使用中,这个例子似乎几乎是无稽之谈。当我无法保护包含函数本身的变量“add”时,为什么要将变量“counter”包装到闭包中,以防止意外修改全局范围?
更具体一点......我有这段代码:
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// the counter is now 3
W3schools在开始时说:“问题是,页面上的任何[全局范围]脚本都可以更改计数器,而无需调用add()。”......上面的闭包提出了一个解决方案。好。但是如何保护“添加”免于订阅?似乎这个解决方案只能解决问题,使这个例子实际上毫无用处。你能告诉我为什么这种副作用不成问题吗?
答案 0 :(得分:4)
在w3schools给出的示例中,他们使用上述闭包解决的问题是保护变量counter
不被直接修改。如果counter
在全局范围内,然后您定义了一个函数,例如add
来将计数器递增一些值,那么您所做的就是为其他代码部分进行交互定义的接口counter
变量。
当您在某些数据和代码库的其他部分之间定义接口时,您可能希望强制执行该接口。换句话说,如果您将counter
放在全局范围内,则无法强制使用您的add
函数,因为我可以这样做:counter += 7
就在全局范围内范围。
将counter
变量包装在闭包中允许您从全局范围隐藏counter
变量,这意味着修改计数器的唯一方法是通过add
函数。这会通过阻止直接修改add
变量的值来强制使用counter
。
所以这是一个简单但很好的例子,说明了如何使用闭包来创建私有变量。
答案 1 :(得分:1)
它没有用,因为它将counter
保留为add
的属性。如果你需要保护add
,你可以将它包装在另一个封闭中。
var add = "something";
(()=>{
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
console.log(add());
console.log(add());
})();
console.log(add);

当然,在现实生活中,你应该首先避免使用超级通用名称,如add
,在现实生活中,如果你需要你的方法来获得属性,你可能会使用OOP代替......
class counter{
constructor(){
this.counter = 0;
}
add(){
this.counter++;
}
}
var c = new counter();
c.add();
c.add();
console.log(c.counter);

如果你只是想确保永远不会重新分配变量名,你可以改用const
(JS"常量")。
const add = (function(){
var add = 0;
return function(){ return ++add };
})();
try{
// this won't work
add = "something";
}catch(e){
console.log(e.message);
}
// Add is still a function here
console.log(add());
console.log(add());
console.log(add());

答案 2 :(得分:0)
为教育目的,示例通常更简单。为了减少他们的注意力。
示例试图显示的是,您只能 使用此闭包增加计数器。你不能减少,你不能到达计数器变量做任何其他事情。你当然可以抛弃整个功能,但这不是你偶然发生的事情。
很容易在闭包中意外更改不变量的值。
答案 3 :(得分:-1)
这是一个“问题较少”和“更有用”的例子。
var fibonacci = (function() {
var memo = {};
return function f(n) {
if (!(n in memo)) {
memo[n] = n === 0 || n === 1 ? n : f(n - 1) + f(n - 2);
}
return memo[n];
}
})();
Closure允许访问“memo”对象,该对象存储以前的所有结果。