跳到主要内容

作用域与闭包

相信读者已经看过很多相关文章,我们这里主要讲一下实战使用。

闭包

几个点理解闭包:

  • JS 中是存在变量作用域的
  • 变量只在作用域内生效
  • 闭包允许作用域之外的程序读取变量

闭包以一种较为可控的形式,将变量共享。

你真的理解了吗?

思考这样一道题(via):

for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(new Date(), i);
}, 1000);
}

console.log(new Date(), i);

输出结果:

Wed Dec 14 2022 16:00:36 GMT+0800 (中国标准时间) 5
Wed Dec 14 2022 16:00:37 GMT+0800 (中国标准时间) 5
Wed Dec 14 2022 16:00:37 GMT+0800 (中国标准时间) 5
Wed Dec 14 2022 16:00:37 GMT+0800 (中国标准时间) 5
Wed Dec 14 2022 16:00:37 GMT+0800 (中国标准时间) 5

结合事件循环的知识,我们可以知道,setTimeout 是异步的,所以会在循环结束后执行五次,而此时 i 已经变成了 5。同时,由于宏任务先进后出的结构,会先执行最后一行的输出,接着循环中的四次输出会一起执行。

第三行中的 i 并非“复制”了一份,而是引用了外部的 i ——这就是闭包的作用。

实际运用

看一个真实的业务代码

    const [history, setHistory] = useState([]);
const [input, setInput] = useInput("");

const handleSend = () => {

setHistory((prevHistory) => [
...prevHistory,
{
type: "human",
text: input,
date: new Date(),
},
]);

axios
.post("/api/apps/openai", /**... */)
.then((res) => {
setHistory((prevHistory) => [
...prevHistory,
{
type: "bot",
text: res.data.choices[0].text,
date: new Date(),
},
]);
setHistory(history); // 注意这一行
});
};
```