JS 中的闭包详解(以 React 为例)
闭包(Closure)是 JavaScript 中非常重要的概念,理解闭包对于掌握作用域、数据保护、回调、React 组件开发等都有极大帮助。
一、什么是闭包?
闭包是指函数能够“记住”并访问它定义时的词法作用域,即使这个函数在其词法作用域之外被调用。
通俗理解:闭包就是“函数+定义该函数的环境”。
形成条件
- 函数嵌套函数
- 内部函数引用了外部函数的变量
- 外部函数返回了内部函数或将其传递到外部
二、闭包的经典例子
1. 基础例子
1 2 3 4 5 6 7 8 9 10
| function makeCounter() { let count = 0; return function () { count++; return count; }; } const counter = makeCounter(); console.log(counter()); console.log(counter());
|
2. 保护变量不被外部直接访问
1 2 3 4 5 6 7 8 9 10 11
| function createPerson(name) { let age = 0; return { getName: () => name, getAge: () => age, grow: () => age++, }; } const tom = createPerson("Tom"); tom.grow(); console.log(tom.getAge());
|
3. 循环中的闭包问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const btns = []; for (var i = 0; i < 3; i++) { btns[i] = function () { console.log(i); }; } btns[0]();
for (let i = 0; i < 3; i++) { btns[i] = function () { console.log(i); }; } btns[0]();
|
三、闭包在 React 中的应用
1. 事件处理中的闭包
1 2 3 4 5 6 7
| function Counter() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return <button onClick={handleClick}>{count}</button>; }
|
2. useEffect 与闭包陷阱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function Timer() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, []); return <div>{count}</div>; }
useEffect(() => { const id = setInterval(() => { setCount((c) => c + 1); }, 1000); return () => clearInterval(id); }, []);
|
3. 自定义 Hook 中的闭包
1 2 3 4 5
| function useCounter() { const [count, setCount] = useState(0); const increment = () => setCount((c) => c + 1); return { count, increment }; }
|
四、闭包的常见用途
- 数据私有化与封装
- 工厂函数、柯里化
- 事件监听、回调
- React 组件状态、Hook
五、闭包的注意事项
- 闭包会导致变量常驻内存,注意内存泄漏
- React 中闭包常见“旧值陷阱”,可用函数式 setState 规避
六、总结
- 闭包是函数+定义环境的组合,能访问外部作用域变量
- React 事件、Hook、定时器等大量用到闭包
- 理解闭包有助于写出更健壮的前端代码
以上内容仅供参考,请结合实际情况具体分析