惰性函数配合闭包实现运行时环境检测,核心是首次调用时完成判断并重写函数,后续直接执行最优路径;闭包保存检测结果确保状态不丢失,避免重复判断、全局污染且接口不变。

惰性函数配合闭包实现运行时环境检测,核心就一句话:只在第一次调用时做判断,之后直接走最优路径。它不是延迟加载资源,而是“延迟定型”——函数自己在首次执行时重写自己,把分支逻辑彻底甩掉。
为什么非得用闭包来配合?
闭包能保存首次检测的结果,并让重写后的函数持续访问这个状态。没有闭包,函数重写后就丢失了上下文;有了闭包,哪怕函数体被替换了,内部仍可复用已确定的环境结论。
- 闭包把检测结果(比如
window.addEventListener是否存在)锁在作用域里,后续调用不查、不问、不犹豫 - 重写函数本身是“自毁式优化”:第一次执行完,原函数就被覆盖成一个极简版本,连
if都没了 - 两者结合,既避免全局变量污染,又杜绝重复判断,还保持接口完全不变
典型写法:立即执行 + 条件重定义
以事件绑定为例,这是最经典的落地场景:
const addEvent = (function () {
if (typeof window.addEventListener === 'function') {
return function (el, type, handler, useCapture = false) {
el.addEventListener(type, handler, useCapture);
};
} else if (typeof window.attachEvent === 'function') {
return function (el, type, handler) {
el.attachEvent('on' + type, handler);
};
} else {
return function (el, type, handler) {
el['on' + type] = handler;
};
}
})();
这段代码在定义时就完成检测,返回一个“已知环境”的函数。后续所有调用都跳过判断,直奔主题。
进阶技巧:首次调用才检测(更灵活)
有些场景不适合在定义时就判断(比如环境可能还没就绪),那就改用“首次调用触发检测+重写”模式:
function addEvent(el, type, handler, useCapture = false) {
if (typeof window.addEventListener === 'function') {
addEvent = function (el, type, handler, useCapture) {
el.addEventListener(type, handler, useCapture);
};
} else if (typeof window.attachEvent === 'function') {
addEvent = function (el, type, handler) {
el.attachEvent('on' + type, handler);
};
} else {
addEvent = function (el, type, handler) {
el['on' + type] = handler;
};
}
// 立即执行当前次调用
return addEvent(el, type, handler, useCapture);
}
这种写法更贴近“惰性”的本意——不急着下结论,等真要用时再判,判完立刻升级自己。
能检测什么?不只是浏览器API
只要是一次判定、长期有效的运行时特征,都适合用这套模式:
- CSS样式获取方式:
getComputedStylevscurrentStyle - Promise是否原生支持,否则 fallback 到 polyfill 函数
- 是否支持 IntersectionObserver,决定懒加载策略
- 用户设备类型(移动端/桌面端)一旦识别,后续无需反复 UA 解析
关键是把“检测逻辑”和“执行逻辑”解耦,让检测只发生一次,执行永远轻量。

















