特性检测比ua嗅探更可靠,应直接检查api是否存在或可调用,如'geolocation' in navigator或typeof promise === 'function',避免依赖易伪造的用户代理字符串和过时版本号。
直接检测浏览器有没有某个功能,比猜它叫什么名字靠谱得多。ua 嗅探容易被伪造、版本一更新就失效、还可能误判——特性检测绕开了这些坑,只关心“这个东西能不能用”。
核心原则:查能力,不查名字
不要写 if (navigator.userAgent.includes('Chrome')),而要写 if ('geolocation' in navigator) 或 if (typeof IntersectionObserver !== 'undefined')。前者依赖字符串匹配,后者检查全局对象或 API 是否真实存在。
- 用
in操作符判断属性是否存在(适合对象上的属性,如'fetch' in window) - 用
typeof判断变量是否为有效类型(避免undefined导致报错,如typeof Promise === 'function') - 对方法可尝试调用
.toString()或检查其.prototype,但通常只需存在性判断
处理 DOM 相关特性的常见写法
很多老项目卡在 querySelectorAll 或 classList 上。IE8 不支持 :nth-child(),但你可以检测 document.querySelectorAll 是否是函数:
if (document.querySelectorAll && typeof document.querySelectorAll === 'function')-
if ('classList' in document.documentElement)—— 这比查 IE 版本号干净利落 - 对
addEventListener,可同时兼容 IE8 的attachEvent,但前提是先确认原生方法不存在再降级
注意别掉进“推断陷阱”
检测到一个特性,并不代表另一个也存在。比如:
- 有
Promise≠ 一定有async/await(IE 和早期 Edge 就不支持后者) - 支持
fetch≠ 支持AbortController - 有
localStorage≠ 它一定能写入(隐私模式下可能抛异常)
每个关键 API 都应单独检测,不拼凑、不假设。
需要兜底时,用现代轻量方案代替 UA 判断
极少数场景真得区分环境(比如微信内嵌浏览器的特定 bug),优先用运行时特征:
- 查
typeof wx !== 'undefined'判断是否在微信小程序环境 - 查
'webkitSpeechRecognition' in window而不是靠 UA 字符串找 Safari - 对已知老 IE 的补丁,可用
!!document.documentMode,它比正则匹配 UA 更稳定可靠
这类判断只用于修复明确 Bug,不用于功能开关主逻辑。











