用 in 检测全局属性最安全,如 'fetch' in window;构造函数需加 typeof === 'function' 防空值;api 存在≠可用,关键功能须试调用;ssr 环境先判 window,动态 polyfill 后需时序保障。

用 in 检测全局对象属性最直接
浏览器是否支持某个 API,本质是看它有没有把对应对象或方法挂到 window(或 self)上。比如 fetch、IntersectionObserver、localStorage 都是直接挂在全局的。
用 in 操作符比 typeof !== 'undefined' 更安全——它不触发访问器异常,也不会因变量未声明而报错。
-
'fetch' in window→ true / false -
'ResizeObserver' in window→ 注意大小写,resizeobserver会返回 false -
'onbeforeinstallprompt' in window→ 这是事件名,不是函数,但仍是可检测的属性
别写 typeof fetch !== 'undefined':在某些老 Safari 或严格模式下,未声明的变量会直接抛 ReferenceError,导致脚本中断。
构造函数检测要加 typeof 防空值
像 Promise、Map、AbortController 这类是构造函数,它们可能被存在,但值为 null 或 undefined(尤其在某些 polyfill 场景或降级环境里)。
立即学习“前端免费学习笔记(深入)”;
只用 in 不够,得再确认类型。
-
typeof Promise === 'function'→ 必须是 function,不能只查'Promise' in window -
typeof Intl?.DateTimeFormat === 'function'→Intl本身可能不存在,用可选链避免报错 -
typeof window.CSS?.supports === 'function'→CSS是命名空间对象,supports是其方法,分开检测更稳
漏掉 typeof 容易在 IE 或旧 Android WebView 中踩坑:比如 Promise 存在但值为 undefined,直接 new Promise() 就崩。
API 方法存在 ≠ 功能可用,得试调用
有些 API 名字在,但内部逻辑不完整。典型如 CSS.supports() 在早期 Chrome 支持语法检测,却不支持 @supports selector();又如 localStorage 在无痕模式下存在,但调用 setItem 会抛 QuotaExceededError。
真要用,就得“浅试”一次:
try { localStorage.setItem('test', '1'); localStorage.removeItem('test'); } catch (e) { /* 不可用 */ }if ('CSS' in window && typeof CSS.supports === 'function') { try { CSS.supports('display', 'grid'); } catch (e) { /* 仍可能失败 */ } }-
if ('navigator' in window && 'permissions' in navigator) { navigator.permissions.query({ name: 'geolocation' }).catch(() => {}); }→ 权限 API 存在,但 query 可能被拒绝或未实现
别省这一步。光看定义不等于能跑通,尤其涉及权限、存储、渲染等受策略限制的功能。
用 Modernizr 太重,轻量方案就两行
Modernizr 做的是全量探测 + class 注入,现在绝大多数项目不需要。自己写个微型检测函数,20 行内搞定。
例如检测 IntersectionObserver 并 fallback:
const supportsIO = 'IntersectionObserver' in window && typeof IntersectionObserver === 'function';
if (!supportsIO) {
// 加载 polyfill 或走定时轮询逻辑
}注意点:
- 不要把所有检测塞进一个对象一次性执行——按需检测,避免提前暴露兼容性逻辑
- 服务端渲染(SSR)环境里
window不存在,检测前先typeof window !== 'undefined' - 动态加载 polyfill 后,别假设“加载完就立刻可用”,要监听
load或用Promise.resolve().then()确保执行时序
特性检测不是一劳永逸的事。同一个 API 在不同版本浏览器里行为可能有细微差异,比如 URLPattern 在 Chrome 110+ 才稳定,之前只是实验性支持——得盯具体版本号,不能只看“存在”。











