function createIncrement(incBy) {
let value = 0;
function increment() {
value += incBy;
console.log(value);
}
const message = `Current value is ${value}`; function log() { console.log(message); }
return [increment, log];
}
const [increment, log] = createIncrement(1);
increment(); // 1
increment(); // 2
increment(); // 3
// 不能正确工作!
log(); // "Current value is 0"
[increment, log] = createIncrement(1)返回一个函数元组:一个函数增加内部值,另一个函数记录当前值。然后,increment()的3次调用将 value递增到3。最后,log()调用打印消息是 Current value is 0,这有点出乎意料的,因为此时 value 为 3 了。$ X1 C0 j! t. C) Y
log()是一个过时的闭包。闭包 log()捕获了值为 "Current value is 0"的 message 变量。即使 value 变量在调用increment()时被增加多次,message变量也不会更新,并且总是保持一个过时的值 "Current value is 0"。过时的闭包捕获具有过时值的变量。6 L7 l8 \6 l' Z 2.修复过时的闭包 V5 @7 r" O* i1 f1 P8 L3 u+ a
修复过时的log()问题需要关闭实际更改的变量:value的闭包。我们将语句 const message = ...; 移动到 log() 函数内部: % o0 X# w% D: B# _; L' E
function createIncrement(incBy) {
let value = 0;
function increment() {
value += incBy;
console.log(value);
}
function log() {
const message = `Current value is ${value}`; console.log(message);
}
return [increment, log];
}
const [increment, log] = createIncrement(1);
increment(); // 1
increment(); // 2
increment(); // 3
// Works!
log(); // "Current value is 3"
现在,在调用了 3 次 increment() 函数之后,调用 log() 记录了实际value:"Current value is 3"。. J+ I7 z/ h/ u2 s' u( m) Z9 ~! b# ? 3. Hooks 中的过时闭包 2 N% f: I* j ?* ^1 j. u3.1 useEffect()2 \) H, j( z# Y
我们来看一下使用useEffect() 过时闭包的常见情况。在组件<WatchCount>中,useEffect() 中每2秒记录一次count的值: W: s8 g X4 S i& i, R5 Z6 L