JavaScript 带反例的闭包问题

JavaScript closure question with counter example

考虑我们有以下片段:

function Counter() {
  let count = 0
  
  function inc() {
    count += 1
  }
  
  function dec() {
    count -= 1
  }
  
  function getCount() {
    return count
  }
  
  return { getCount, inc, dec, count }
}

const counter = Counter()
counter.inc()
counter.inc()

console.log(counter.getCount()) // 2
console.log(counter.count) // 0

我想知道为什么使用函数 getCount() 和直接 return count 变量显示不同的结果。在我看来,它们都引用了相同的 count 地址,并且在 inc() 调用之后它的值应该相应地改变。

主要是因为您从函数返回的 count 是变量的副本(value 更准确)而 getCount 是一个函数,它指的是 count 变量的引用。你可以学到更多 here.

return { getCount, inc, dec, count }:

  1. 创建一个新对象
  2. 将这四个变量的当前值复制到具有相同名称的属性
  3. Returns那个对象

当您更改 count 变量的值时,您不会更改 count 属性.

的值

原因是因为当您执行 counter.count 时,您正在获取返回的新对象的计数值。该计数实际上是创建时值的副本,永远不会更新。

如果相反,您创建 class 并使用 this.count,它将始终更新。

class Counter {
  constructor() {
    this.count = 0;
  }
  
  inc() {
    this.count += 1;
  }
  
  dec() {
    this.count -= 1;
  }
  
  getCount() {
    return this.count;
  }
}

const counter = new Counter();
counter.inc()
counter.inc()

console.log(counter.getCount()) // 2
console.log(counter.count) // 2

或者,如果你想用更老派的方式来做:

function Counter() {
  this.count = 0
  
  function inc() {
    count += 1
  }
  
  function dec() {
    count -= 1
  }
  
  function getCount() {
    return count
  }
  
  this.inc = inc;
  this.dec = dec;
  this.getCount = getCount;
  
  return this;
}

const counter = Counter()
counter.inc()
counter.inc()

console.log(counter.getCount()) // 2
console.log(counter.count) // 2

或者,您可以使 count 和对象具有一些可以更新的值:

function Counter() {
  let count = { value: 0 }
  
  function inc() {
    count.value += 1
  }
  
  function dec() {
    count.value -= 1
  }
  
  function getCount() {
    return count.value
  }
  
  return { getCount, inc, dec, count }
}

const counter = Counter()
counter.inc()
counter.inc()

console.log(counter.getCount()) // 2
console.log(counter.count.value) // 2

虽然最后一个对于这个特定的用例来说有点傻。

因为在 getCount() 中您正在重新分配 count 的值,即 count = count + 1