Skip to content

ES6 - 浏览器

虽然 ES6 (ECMAScript 2015) 及更高版本的 JavaScript 现在已得到现代浏览器的广泛支持,但了解浏览器环境、其 [API] 以及如何编写兼容代码仍然非常重要。这涉及到了解 navigator 对象,更重要的是,倾向于使用[特性检测 (feature detection)] 而不是[浏览器嗅探 (browser sniffing)]。

navigator 对象是 window 对象的一个属性,包含有关浏览器(用户代理)的信息。虽然它提供了各种属性,但通常不建议依赖它们来控制应用程序逻辑(即[浏览器嗅探])。

属性描述
navigator.userAgent一个字符串,包含浏览器发送到服务器的用户代理头部信息。通常很复杂,并且可以被伪造。主要用于分析或调试,不应用于[特性检测]。
navigator.language一个字符串,表示用户的首选语言,通常是浏览器 UI 的语言(例如,“en-US”)。
navigator.languages一个字符串数组,表示用户的首选语言,按偏好排序。
navigator.onLine一个布尔值,表示浏览器当前是否有互联网连接(true)或没有(false)。
navigator.platform一个字符串,标识浏览器运行所在的平台(例如,“Win32”、“MacIntel”、“Linux x86_64”)。可能具有误导性,并且不如特定的[特性检测]可靠。
navigator.cookieEnabled一个布尔值,表示浏览器中是否启用了 cookie。
navigator.geolocation返回一个 Geolocation 对象,可用于获取用户位置(需要用户许可)。
navigator.mediaDevices提供对连接的媒体输入设备(如摄像头和麦克风)的访问(需要用户许可)。
navigator.connection提供有关系统连接的信息,例如当前的有效连接类型(例如,“4g”)。(实验性,支持情况各异)

已弃用或不太可靠的 navigator 属性:

较旧的教程可能会提及 navigator.appName、navigator.appCodeName 或 navigator.appVersion 等属性。出于兼容性原因,这些属性大都已弃用或返回固定值(例如,appName 通常无论浏览器是什么都返回 “Netscape”),不应再用于确定浏览器功能。

[浏览器嗅探]涉及检查 navigator.userAgent 字符串以识别浏览器及其版本,然后根据此检测更改代码行为。出于以下几个原因,强烈不建议采用这种做法:

  • 脆弱性:用户代理字符串可以被用户或浏览器扩展轻松更改。
  • 不准确性:浏览器可能会在用户代理字符串中撒谎,以绕过网站上编写不良的嗅探代码。
  • 维护噩梦:新浏览器和版本频繁发布,需要不断更新嗅探逻辑。
  • 关注实现而非特性:嗅探假设某个浏览器具有或缺少某个特性,但这可能并不总是真的,或可能在未来版本中改变。
// 这是一个不应使用浏览器嗅探进行特性控制的示例
function oldBrowserDetection() {
const userAgent = navigator.userAgent;
if (userAgent.includes('MSIE') || userAgent.includes('Trident/')) {
console.log('This might be Internet Explorer.');
// ... 应用 IE 特定的逻辑(过时的方法)
} else if (userAgent.includes('Firefox')) {
console.log('This might be Firefox.');
} else if (userAgent.includes('Chrome')) {
console.log('This might be Chrome.');
} else {
console.log('未知浏览器或现代 Edge(基于 Chromium)。');
}
}
oldBrowserDetection();

上面的代码尝试识别浏览器。然而,基于 Chromium 的现代 Edge 浏览器也会在其用户代理中包含 ‘Chrome’,如果逻辑没有经过仔细设计和不断更新,可能会导致潜在的错误识别。

与其问“这是什么浏览器?”,不如问“这个浏览器支持我需要的特性吗?”。这就是[特性检测]。在使用某个对象、方法或属性之前,直接检查它是否存在并且行为是否符合预期。

// 检查是否支持 Promise(ES6 特性)
if (window.Promise) {
console.log('Promises are supported.');
// 使用 Promises
} else {
console.log('Promises are NOT supported. Consider a polyfill or alternative.');
// 回退逻辑
}
// 检查是否支持 Geolocation API
if ('geolocation' in navigator) {
console.log('Geolocation API is available.');
navigator.geolocation.getCurrentPosition(position => {
console.log('Latitude:', position.coords.latitude);
console.log('Longitude:', position.coords.longitude);
}, error => {
console.error('获取位置出错:', error.message);
});
} else {
console.log('不支持 Geolocation API。');
}
// 检查元素上是否支持特定方法(例如 requestFullscreen)
const myElement = document.documentElement; // 或任何其他元素
if (myElement.requestFullscreen) {
console.log('元素支持 requestFullscreen。');
// myElement.requestFullscreen(); // 示例用法
} else if (myElement.mozRequestFullScreen) { // Firefox 特有的(较旧的)
console.log('元素支持 mozRequestFullScreen。');
// myElement.mozRequestFullScreen();
} else if (myElement.webkitRequestFullscreen) { // Webkit 特有的
console.log('元素支持 webkitRequestFullscreen。');
// myElement.webkitRequestFullscreen();
} else if (myElement.msRequestFullscreen) { // IE/Edge 特有的(较旧的)
console.log('元素支持 msRequestFullscreen。');
// myElement.msRequestFullscreen();
} else {
console.log('此元素不支持 Fullscreen API。');
}

[特性检测]使得代码更健壮、更面向未来且更易于维护,因为它关注的是实际功能,而不是基于浏览器身份的假设。

当需要支持的旧版浏览器中不提供现代 JavaScript 特性时:

  • [Polyfill]:一段代码 (JavaScript),它在原生不支持某个现代 [API] 或特性的旧版浏览器中提供该功能。例如,如果 window.Promise 未定义,[Promise] [polyfill] 将实现 [Promise] 对象。
  • [Transpiler]:像 [Babel] 这样的工具,将现代 JavaScript 代码(例如 ES6+ 语法,如箭头函数、类)转换成具有更广泛浏览器兼容性的旧版本 JavaScript(例如 ES5)。这使得开发者可以编写现代代码,同时确保它在更多环境中运行。

使用[特性检测]、[Polyfill]和[Transpiler]可以使开发者利用现代 JavaScript 能力,同时优雅地处理那些原生不支持这些功能的环境。