关于javascript闭包的w3schools例子几乎没用吗?

时间:2018-02-12 14:42:20

标签: javascript closures counter

我正在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()。”......上面的闭包提出了一个解决方案。好。但是如何保护“添加”免于订阅?似乎这个解决方案只能解决问题,使这个例子实际上毫无用处。你能告诉我为什么这种副作用不成问题吗?

4 个答案:

答案 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”对象,该对象存储以前的所有结果。