1. JavaScript 中的闭包 ```javascript function createIncrement(i) { let value = 0; function increment() { value += i; console.log(value); } return increment; }

    const inc = createIncrement(1); inc(); // 1 inc(); // 2

    1. - 当在函数上返回一个函数时,有会有闭包产生。闭包捕获词法作用域中的变量 value i。词法作用域是定义闭包的外部作用域。在本例中,increment() 的词法作用域是createIncrement()的作用域,其中包含变量 value i
    2. - 闭包原理:闭包是基于正常的垃圾回收处理机制下的,也就是说,一般情况一个函数(函数作用域)执行完毕,里面声明的变量会全部释放,被垃圾回收器回收,但是有一些变量在函数执行完毕后还有可能被使用的话,就不会被垃圾回收器回收。闭包就是利用了一个技巧,让作用域里面的变量,在函数执行完之后还可以被使用。
    3. 2. JavaScript 中的过时闭包
    4. ```javascript
    5. function createIncrement(i) {
    6. let value = 0;
    7. function increment() {
    8. value += i;
    9. console.log(value);
    10. const message = `Current value is ${value}`;
    11. return function logValue() {
    12. console.log(message);
    13. };
    14. }
    15. return increment;
    16. }
    17. const inc = createIncrement(1);
    18. const log = inc(); // 打印 1
    19. inc(); // 打印 2
    20. inc(); // 打印 3
    21. log(); // 打印 "Current value is 1"
    • log()是过时的闭包。在第一次调用 inc() 时,闭包 log() 捕获了具有 “Current value is 1” 的 message 变量。而现在,当 value 已经是 3 时,message 变量已经过时了。
    1. 解决js中的过时闭包 ```javascript //解决过时闭包的第一种方法是找到捕获最新变量的闭包。找到捕获了最新 message 变量的闭包。就是从最后一次调用 inc() 返回的闭包。 const inc = createIncrement(1);

    inc(); // 打印 1 inc(); // 打印 2 const log = inc(); // 打印 3 log(); // 打印 “Current value is 3”

    1. 4. useEffect() 中的过时闭包
    2. ```javascript
    3. function WatchCount() {
    4. const [count, setCount] = useState(0);
    5. useEffect(function() {
    6. setInterval(function log() {
    7. console.log(`Count is: ${count}`);
    8. }, 2000);
    9. }, []);
    10. return (
    11. <div>
    12. {count}
    13. <button onClick={() => setCount(count + 1) }>
    14. 加1
    15. </button>
    16. </div>
    17. );
    18. }
    19. //现象:单击几次加1按钮,然后看看控制台,每2秒打印 Count is: 0
    20. //原因:第一次渲染时,状态变量count初始化为0。useEffect()调用setInterval(log, 2000)计时器函数,该计时器函数计划每2秒调用一次log()函数。 在这里,闭包log()捕获到count变量为0。之后,即使在单击Increase按钮时count增加,计时器函数每2秒调用一次的log(),使用count的值仍然是0。log()成为一个过时的闭包。
    21. //源码层面:hook的源码中,每一个setCount执行后,会把当前的count丢到一个hook的链表上。每执行一次,就变成了hook.next = newhook这种感觉。setInterval每次打印的count都是时执行useEffect那个时候的count,实际上就是hook.next.count,后面再执行setCount只不过是往hook链表上新的{val:{count:x}}
    1. 解决useEffect()的过时闭包 ```javascript function WatchCount() { const [count, setCount] = useState(0);

      useEffect(function() { const id = setInterval(function log() { console.log(Count is: ${count}); }, 2000); return function() { clearInterval(id); } }, [count]); return (

      1. {count}
      2. <button onClick={() => setCount(count + 1) }>
      3. Increase
      4. </button>

      ); }

    ```