前端闭包的5大实际应用场景(附面试加分示例)
一、模块化封装(隔离作用域)
核心场景:避免全局变量污染,实现私有变量和方法的封装。
示例:封装工具函数库(如防抖节流、工具类):
const utils = (() => {
// 私有变量(外部无法直接访问)
const privateKey = "xxx";
return {
getEncrypted: (data) => {
// 利用闭包访问privateKey
return encrypt(data, privateKey);
},
formatTime: (time) => format(time) // 暴露公共方法
};
})();
utils.getEncrypted("test"); // 可访问
utils.privateKey; // undefined(无法访问私有变量)
面试加分:提及 “IIFE(立即执行函数)+ 闭包” 是 ES6 模块普及前的核心模块化方案。
二、状态维持(保留变量上下文)
核心场景:需要持续追踪状态的功能(计数器、表单状态、缓存)。
示例 1:计数器:
function createCounter() {
let count = 0; // 闭包保留count状态
return {
increment: () => count++,
getCount: () => count
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2(状态持续保留)
示例 2:请求缓存:
function createRequestCache() {
const cache = {}; // 闭包缓存请求结果
return async (url) => {
if (cache[url]) return cache[url];
const res = await fetch(url);
cache[url] = res.json();
return cache[url];
};
}
const request = createRequestCache();
request("/api/data"); // 首次请求,缓存结果
request("/api/data"); // 直接返回缓存(避免重复请求)
三、防抖与节流函数(面试高频)
核心场景:限制高频事件触发(滚动、输入、点击),优化性能。
示例:防抖函数(输入框搜索联想) :
function debounce(fn, delay) {
let timer = null; // 闭包保存定时器ID
return (...args) => {
clearTimeout(timer); // 清除上一次定时器
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 应用:输入框搜索(停止输入300ms后执行)
const search = debounce((value) => fetch(`/api/search?key=${value}`), 300);
input.addEventListener("input", (e) => search(e.target.value));
四、函数柯里化(参数复用)
核心场景:将多参数函数转化为单参数函数,复用前置参数。
示例:用户权限校验:
// 柯里化函数:先传入权限阈值,再传入用户权限
function checkPermission(requiredRole) {
// 闭包保留requiredRole
return (userRole) => userRole >= requiredRole;
}
// 复用:创建“管理员权限校验”和“普通用户校验”
const isAdmin = checkPermission(3);
const isNormalUser = checkPermission(1);
isAdmin(3); // true(管理员)
isNormalUser(2); // true(普通用户)
五、React/Vue 中的闭包应用
核心场景:组件状态持久化、钩子函数中保留上下文。
示例 1:React 自定义 Hook(保留定时器) :
function useInterval(callback, delay) {
const savedCallback = useRef();
// 闭包保存最新callback(避免依赖更新问题)
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const timer = setInterval(() => savedCallback.current(), delay);
return () => clearInterval(timer); // 清除定时器
}, [delay]);
}
示例 2:Vue 生命周期中保存数据:
export default {
mounted() {
const initialData = this.formData; // 闭包保留初始值
this.$watch("formData", (newVal) => {
// 对比当前值与初始值(initialData通过闭包访问)
if (JSON.stringify(newVal) !== JSON.stringify(initialData)) {
this.isModified = true;
}
});
}
};