Javascript ES6浏览器检测 [英] Javascript ES6 cross-browser detection

查看:154
本文介绍了Javascript ES6浏览器检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何找到浏览器的JavaScript引擎版本和对ECMAScript 6的支持?



我使用 navigator.appVersion 只是为了知道浏览器的版本,而不是引擎的版本。

解决方案

功能检测



我建议您使用 功能检测 ,而不是使用启发式方法检测浏览器的引擎。为此,您可以简单地 try {..} catch(e){...} 语句中包装一些代码,或使用一些 if(...)语句



例如:

  function check(){
if(typeof SpecialObject ==undefined)return false;
try {specialFunction(); }
catch(e){return false; }

return true;
}

if(check()){
//使用SpecialObject和specialFunction
} else {
//你不能使用它们:(
}



为什么功能检测比浏览器/引擎检测更好?



在大多数情况下,多种原因使特征检测成为最佳选择:




  • 您不必依赖浏览器的版本,引擎或细节,也不用使用启发式方法来检测它们,这些启发式方法实施起来很难,而且很诡异。


  • 您不会遇到有关浏览器/引擎规格检测的错误。


  • 您不必担心浏览器特定的功能:例如 WebKit 浏览器的规格与其他浏览器不同。


  • 您可以确定,一旦检测到功能,您就可以使用该功能。




这些是IMHO使功能检测成为最佳方法的主要原因。



功能检测+回退



使用 功能检测 时,一种非常聪明的方式可以在不确定哪些功能无法使用的情况下使用,这在多个功能检测和(或甚至从头开始创建这些方法),以避免不支持要使用的功能。



具有回退功能检测功能的简单示例可能会应用于所有浏览器不支持的 window.requestAnimationFrame 功能,并具有几个不同的前缀,具体取决于您正在使用的浏览器。在这种情况下,您可以轻松地检测和回退

  requestAnimationFrame = 
window.requestAnimationFrame //标准名称
|| window.webkitRequestAnimationFrame //回退到webkit-(旧版本的Chrome或Safari)
|| window.mozRequestAnimationFrame //返回到moz-(Mozilla Firefox)
||假; //功能不支持:(

//同样的cancelAnimationFrame
cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || false;

if(!requestAnimationFrame){
//不支持?自己构建
requestAnimationFrame = function(callback){
return setTimeout(callback,0);
}

//没有requestAnim意味着没有cancelAnim也建立了
cancelAnimationFrame = function(id){
clearTimeout(id);
}
}

//现在你可以使用requestAnimationFrame
//无论你运行哪个浏览器
var animationID = requestAnimationFrame(myBeautifulFunction);



ECMAScript 6(Harmony)功能检测



现在,来到真正的问题:如果你想检测到对ES6的支持,你将无法像上面所说的那样,因为 ES6功能的相关范围基于新的语法和私有字,如果在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; }
//这个线将始终在ES5中抛出一个SyntaxError
//甚至在检查ES6
之前//因为包含非法语法
} else {
var bar = function(arg){return arg; }
}

现在,既然你不能同时检查和执行ES6脚本,,您必须编写两个不同的脚本:仅使用ES5的脚本,另一个脚本包含ES6功能。使用两个不同的脚本,只有在支持时才能导入ES6,而不会导致引发 SyntaxErrors p>

ES6检测和条件执行示例



现在让我们做一个更可靠的例子,让我们假设你要使用这些您的ES6脚本中的功能:




  • 新的符号对象

  • 使用类构建的类<​​/ code>关键字

  • 箭头((...)= > {...} )函数



注意 的特征检测(如箭头函数)只能使用 eval()函数或其他等价物(例如 Function()),因为写入无效的语法将在执行脚本之前停止脚本。这也是为什么你不能使用如果语句来检测类和箭头函数的原因:这些功能是关于关键字和语法,所以一个 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()){
    //引擎支持您要使用的ES6功能
    var s = document.createElement('script') ;
    s.src =es6script.js;
    document.head.appendChild(s);
    } else {
    //引擎不支持那些ES6功能
    //使用无聊的ES5 :(
    }


  • 您的 es6script.js 中的代码:

      //只是例如... 
    use strict;

    class Car {// yay!
    构造函数(速度){
    this.speed = speed;
    }
    }

    var foo = Symbol('foo'); // wohoo!
    var bar = new Car(320); // blaze it!
    var baz =(name)=> {alert('Hello'+ name +'!');}; //很酷!




浏览器/引擎检测



检查检测浏览器< a>关于这个主题的更多信息和例子。






像上面所说的,浏览器和引擎检测不是最佳做法当编程一些JavaScript脚本,我会gi你有一些关于这个话题的背景,只是不要把我的话作为一个随机的个人意见。



从MDN文档引用[链接]:


当考虑使用用户代理字符串来检测正在使用哪个浏览器时,您的第一步是尽可能地避免使用。开始尝试确定你想要做的事情。



[...] 您是否试图检查特定功能的存在? strong>
您的网站需要使用某些浏览器尚不支持的特定Web功能,并且您希望将这些用户发送到具有较少功能的旧网站,但您知道将会工作。这是使用用户代理检测的最糟糕的原因,因为最终所有其他浏览器都会赶上。您应该尽最大努力避免在这种情况下使用用户代理嗅探,而执行功能检测


另外,你在说你使用 navigator.appVersion ,但是考虑使用另一种方法,因为这个方法与许多其他导航器属性一起被,并不总是像你想的那样。



所以,引用MDN文档[ link ]再次:


已弃用:此功能已从Web标准中移除。虽然一些浏览器可能仍然支持它,但它正在被丢弃。不要在旧的或新的项目中使用它。



注意:不要依赖此属性返回正确的浏览器版本。在基于Gecko的浏览器(如Firefox)和基于WebKit的浏览器(如Chrome和Safari)中,返回值以5.0开头,后跟平台信息。在Opera 10和更新版本中,返回的版本与实际的浏览器版本不符。



How can I find out the browser's Javascript engine version and support to ECMAScript 6?

I'm using navigator.appVersion just to know the browser's version, but not the engine's version.

解决方案

Feature detection

I suggest you to use feature detection instead of detecting the browser's engine with heuristic methods. To do this you can simply wrap some code inside a try {..} catch (e) {...} statement, or use some if (...) statements.

For example:

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 :(
}

Why is feature detection better than browser/engine detection?

There are multiple reasons that make, in most of the cases, feature detection the best option:

  • You don't have to rely on browser's version, engine or specifics, nor detect them using heuristic methods which are hard and pretty crafty to implement.

  • You will not fall into errors regarding browser/engine specifications detection.

  • You don't have to worry about browser-specific features: for example WebKit browsers have different specifications than other ones.

  • You can be sure that, once a feature is detected, you'll be able to use it.

These are the main reasons that IMHO make feature detection the best approach.

Feature detection + fallback

When using feature detection, a pretty smart way to work when you aren't sure which features you can/cannot use consists in several feature detections and consequent fallbacks to more basic methods (or even creation of these methods from scratch) in case the features you want to use are not supported.

A simple example of feature detection with fallback may be applied to the window.requestAnimationFrame feature, which is not supported by all the browsers, and has several different prefixes depending on the browser you're working on. In this case, you can easily detect and fallback like this:

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 (Harmony) features detection

Now, coming to the real problem: if you want to detect the support to ES6, you'll not be able to behave like I said above, because a relevant range of ES6 features is based on new syntaxes and private words, and will throw a SyntaxError if used in ES5, which means that writing a script which contains both ES5 and ES6 is impossible!

Here is an example to demonstrate this issue; the below snippet won't work, and it will be blocked before execution because contains illegal syntax.

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; }
}

Now, since that you cannot both check and execute ES6 conditionally in the same script, you'll have to write two different scripts: one which only uses ES5, and another one which includes ES6 features. With two different scripts you'll be able to import the ES6 one only if it is supported, and without causing SyntaxErrors to be thrown.

ES6 detection and conditional execution example

Now let's make a more relatable example, and let's say you want to use these features in your ES6 script:

  • The new Symbol objects
  • Classes built with the class keyword
  • Arrow ((...)=>{...}) functions

NOTE: feature detection of newly introduced syntaxes (like arrow functions) can only be done using the eval() function or other equivalents (e.g. Function()), because writing invalid syntax will stop the script before its execution. This is also the reason why you cannot use if statements to detect classes and arrow functions: these features are regarding keywords and syntax, so an eval(...) wrapped inside a try {...} catch (e) {...} block will work fine.

So, coming to the real code:

  • HTML Markup:

    <html>
        <head>
            <script src="es5script.js"></script>
        </head>
        <body>
            <!-- ... -->
        </body>
    </html>
    

  • Code in your es5script.js script:

    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 :(
    }
    

  • Code in your 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!
    

Browser/engine detection

Check Detecting browser more info and examples on this topic.


Like I said above, browser and engine detection are not the best practices when programming some JavaScript script. I'm gonna give you some background on this topic, just not to leave my words as a "random personal opinion".

Quoting from the MDN Documentation [link]:

When considering using the user agent string to detect which browser is being used, your first step is to try to avoid it if possible. Start by trying to identify why you want to do it.

[...] Are you trying to check for the existence of a specific feature? Your site needs to use a specific Web feature that some browsers don't yet support, and you want to send those users to an older Web site with fewer features but that you know will work. This is the worst reason to use user agent detection, because odds are eventually all the other browsers will catch up. You should do your best to avoid using user agent sniffing in this scenario, and do feature detection instead.

Also, you're saying you use navigator.appVersion, but consider using another approach, because that one, together with many other navigator properties, is deprecated, and doesn't always behave like you think.

So, quoting from the MDN Documentation [link] again:

Deprecated: this feature has been removed from the Web standards. Though some browsers may still support it, it is in the process of being dropped. Do not use it in old or new projects. Pages or Web apps using it may break at any time.

Note: Do not rely on this property to return the correct browser version. In Gecko-based browsers (like Firefox) and WebKit-based browsers (like Chrome and Safari) the returned value starts with "5.0" followed by platform information. In Opera 10 and newer the returned version does not match the actual browser version, either.

这篇关于Javascript ES6浏览器检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆