在功能中更新/检索私人计数器

时间:2016-01-11 04:07:05

标签: javascript function object closures counter

我在下面创建了一个更新私有计数器的函数,该私有计数器只能通过此函数中的另一个嵌套函数访问。

var private = function() {
  var counter = 0;
  return {
    add: function(increment) { counter += increment},
    retrieve: function() { console.log('the counter is currently set to ' + counter)}
  }
}

这是一个句法问题。我无法通过以下方式访问函数来更新/检索计数器:

private().add(5);
private().retrieve(); // should return 5, but returns 0

然而,以相同的方式调用函数,但添加变量" p"以某种方式使它工作!

var p = private();
p.add(5);
p.retrieve(); //actually returns 5

我的生活不能解决这个问题。任何有关这方面的指导将不胜感激。

尝试在此网站上搜索其他问题,但无法在此处找到解决方案:

accessing variables in javascript closures

1 个答案:

答案 0 :(得分:7)

这称为"factory function",它创建一个“安全”lexical scope,这意味着函数中包含的变量不能被更改或以其他方式从全局范围访问。

对工厂函数的每次调用(代码中的每个private()实例)都会再次调用工厂函数,从而创建一个新的范围。当您指定返回的值private()时,它会将返回的对象及其对创建它的词法作用域的访问权限保存到该变量。

使用Immediately Invoked Function Expression语法(以下简称IIFE),我们可以扩展示例以显示正在发生的事情。

第一个例子:

private().add(5);
private().retrieve();

扩展如下:

(function(){
  var counter = 0;
  return {
    add: function(increment) { counter += increment},
    retrieve: function() { console.log('the counter is currently set to ' + counter)}
  };
})().add(5);
(function(){
  var counter = 0;
  return {
    add: function(increment) { counter += increment},
    retrieve: function() { console.log('the counter is currently set to ' + counter)}
  };
})().retrieve();

虽然第二个例子:

var p = private();
p.add(5);
p.retrieve();

扩展如下:

var p = (function(){
  var counter = 0;
  return {
    add: function(increment) { counter += increment},
    retrieve: function() { console.log('the counter is currently set to ' + counter)}
  };
})();
p.add(5);
p.retrieve();

这就是为什么第一个例子没有提供预期的输出,第二个例子呢。

因此,如果您只想要一个安全范围,并且以后不需要创建新范围,那么IIFE就足够了。

var private = (function() {
  var counter = 0;
  return {
    add: function(increment) { counter += increment},
    retrieve: function() { console.log('the counter is currently set to ' + counter)}
  }
})();

private.add(5);
private.retrieve(); // the counter is currently set to 5
private.add(5);
private.retrieve(); // the counter is currently set to 10