Javascript ES6跨浏览器检测
我怎样才能找出浏览器的Javascript引擎版本,并支持ECMAScript 6?
我使用navigator.appVersion
只是为了了解浏览器的版本,而不是引擎的版本。
特征检测
我build议你使用function检测,而不是用启发式方法检测浏览器的引擎。 要做到这一点,你可以简单地在try {..} catch (e) {...}
语句中包装一些代码,或者使用一些if (...)
语句 。
例如:
function check() { if (typeof SpecialObject == "undefined") return false; try { specialFunction(); } catch (e) { return false; } return true; } if (check()) { // Use SpecialObject and specialFunction } else { // You cannot use them :( }
为什么function检测比浏览器/引擎检测更好?
在大多数情况下,有多种原因可以使特征检测成为最佳select:
-
您不必依靠浏览器的版本,引擎或细节,也不需要使用启发式方法来检测它们,这些方法很难实施,而且相当狡猾。
-
你不会陷入有关浏览器/引擎规格检测的错误。
-
您不必担心浏览器特定的function:例如, WebKit浏览器的规格与其他规格不同。
-
您可以确定,一旦检测到function,您就可以使用它。
这些是恕我直言使特征检测成为最佳方法的主要原因。
function检测+回退
在使用特征检测时 ,如果您不确定哪些function可以/不可以使用,那么使用function检测的一个非常聪明的方法就是检测多个function并随后回退到更基本的方法 (甚至从头开始创build这些方法)你想使用不支持。
一个简单的function检测示例可以应用于window.requestAnimationFrame
function,该function不受所有浏览器支持,并且具有多个不同的前缀,具体取决于您正在使用的浏览器。 在这种情况下,您可以轻松检测并回退,如下所示:
requestAnimationFrame = window.requestAnimationFrame // Standard name || window.webkitRequestAnimationFrame // Fallback to webkit- (old versions of Chrome or Safari) || window.mozRequestAnimationFrame // Fallback to moz- (Mozilla Firefox) || false; // Feature not supported :( // Same goes for cancelAnimationFrame cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || false; if (!requestAnimationFrame) { // Not supported? Build it by yourself! requestAnimationFrame = function(callback) { return setTimeout(callback, 0); } // No requestAnim. means no cancelAnim. Built that too. cancelAnimationFrame = function(id) { clearTimeout(id); } } // Now you can use requestAnimationFrame // No matter which browser you're running var animationID = requestAnimationFrame(myBeautifulFunction);
ECMAScript 6(和声)function检测
现在,出现真正的问题 :如果你想检测对ES6的支持,你将无法像上面所说的那样行事,因为相关的ES6function范围是基于新的语法和私有的话,并且会抛出如果在ES5中使用了SyntaxError
,这意味着写一个包含ES5和ES6的脚本是不可能的!
下面是一个例子来说明这个问题。 下面的代码片段将不起作用,并且在执行之前会被阻塞,因为包含非法的语法。
function check() { "use strict"; try { eval("var foo = (x)=>x+1"); } catch (e) { return false; } return true; } if (check()) { var bar = (arg) => { return arg; } // THIS LINE will always throw a SyntaxError in ES5 // Even before checking for ES6 // Because contains illegal syntax } else { var bar = function(arg) { return arg; } }
现在,既然你不能在同一个脚本中有条件地检查和执行ES6, 你必须写两个不同的脚本 :一个只使用ES5,另一个使用ES6function。 使用两种不同的脚本, 只有支持ES6,才能导入ES6 ,而不会引发SyntaxErrors
。
ES6检测和条件执行的例子
现在我们来创build一个更具关联性的示例,假设您想在ES6脚本中使用这些function:
- 新的
Symbol
对象 - 用
class
关键字构build的class
- 箭头(
(...)=>{...}
)函数
注意: 只能使用eval()
函数或其他等价物(例如Function()
) 完成 新引入的语法 (如箭头函数)的function检测 ,因为编写无效的语法会在脚本执行之前停止。 这也是为什么你不能使用if
语句来检测类和箭头函数的原因:这些特性是关于关键字和语法的,所以一个eval(...)
包装在try {...} catch (e) {...}
块将工作正常。
所以,来到真正的代码:
-
HTML标记:
<html> <head> <script src="es5script.js"></script> </head> <body> <!-- ... --> </body> </html>
-
代码在你的
es5script.js
脚本中:function check() { "use strict"; if (typeof Symbol == "undefined") return false; try { eval("class Foo {}"); eval("var bar = (x) => x+1"); } catch (e) { return false; } return true; } if (check()) { // The engine supports ES6 features you want to use var s = document.createElement('script'); s.src = "es6script.js"; document.head.appendChild(s); } else { // The engine doesn't support those ES6 features // Use the boring ES5 :( }
-
代码在你的
es6script.js
:// Just for example... "use strict"; class Car { // yay! constructor(speed) { this.speed = speed; } } var foo = Symbol('foo'); // wohoo! var bar = new Car(320); // blaze it! var baz = (name) => { alert('Hello ' + name + '!'); }; // so cool!
浏览器/引擎检测
就像我上面所说的,在编写JavaScript脚本时,浏览器和引擎检测并不是最好的实践。 我会给你一些关于这个话题的背景,只是不要把我的话说成是“随意的个人意见”。
引用MDN文档[ 链接 ]:
在考虑使用用户代理string来检测正在使用的浏览器时,如果可能的话,您的第一步是尽量避免它。 首先尝试确定你为什么要这样做。
[…] 你是否试图检查一个特定的function的存在? 您的网站需要使用某些浏览器尚不支持的特定networkingfunction,并且您希望将这些用户发送到function较less的较旧的网站,但您知道该function可以正常工作。 这是使用用户代理检测的最糟糕的原因,因为最终所有其他浏览器都会赶上。 您应该尽可能避免在此情况下使用用户代理嗅探, 而是执行function检测 。
此外,你说你使用navigator.appVersion
,但考虑使用另一种方法,因为那个,连同许多其他的导航属性,已被弃用 ,并不总是像你想象的那样。
所以,再次从MDN文档[ link ]引用:
弃用 :此function已从Web标准中删除。 尽pipe一些浏览器可能仍然支持它,但它正在被丢弃。 不要在旧的或新的项目中使用它。 使用它的页面或Web应用程序可能会随时中断。
注意:不要依赖此属性来返回正确的浏览器版本。 在基于Gecko的浏览器(如Firefox)和基于WebKit的浏览器(如Chrome和Safari)中,返回的值以“5.0”开始,接着是平台信息。 在Opera 10和更新版本中,返回的版本与实际的浏览器版本不匹配。
使用下面的代码来检测它。 它在我的浏览器上工作,你会看到Firefox上的ES6 🙂
- 检测WebKit中的特殊属性devicePixelRatio。
- 检测javaEnabled函数的工具。
(function() { var v8string = 'function%20javaEnabled%28%29%20%7B%20%5Bnative%20code%5D%20%7D'; var es6string = 'function%20javaEnabled%28%29%20%7B%0A%20%20%20%20%5Bnative%20code%5D%0A%7D'; if (window.devicePixelRatio) //If WebKit browser { var s = escape(navigator.javaEnabled.toString()); if (s === v8string) { alert('V099787 detected'); } else if (s === es6string) { alert('ES6 detected') } else { alert('JSC detected'); } } else { display("Not a WebKit browser"); } function display(msg) { var p = document.createElement('p'); p.innerHTML = msg; document.body.appendChild(p); } })()
目前还没有确切的方法来检测ES6,但是如果您在当前浏览器中testing其function,则可以确定引擎是否为ES6。 我的esx库通过执行语法testing和方法检查来检测ECMAScript版本。 为了知道它可以检测ECMAScript 3,5,6和7(ES7没有testing,但应该工作),如果没有ECMAScripttesting匹配,结果为null
。
使用我的库的示例:
if (esx.detectVersion() >= 6) { /* We're in ES6 or above */ }