跳到主要内容

作用域与闭包

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

闭包

几个点理解闭包:

  • 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); // 注意这一行
	});
};