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 }
:
- 创建一个新对象
- 将这四个变量的当前值复制到具有相同名称的属性
- 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
考虑我们有以下片段:
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 }
:
- 创建一个新对象
- 将这四个变量的当前值复制到具有相同名称的属性
- 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