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

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

问题描述

如何查看浏览器的Javascript引擎版本以及对ECMAScript 6的支持?

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

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

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

推荐答案

特征检测

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

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.

例如:

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.

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

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.

使用特征检测时,当您不确定可以/不能使用哪些特征时,一种非常聪明的工作方式是几个特征检测和如果不支持您要使用的功能,则回退到更基本的方法(甚至从头开始创建这些方法).

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.

带有回退功能的特征检测的一个简单示例可以应用于 window.requestAnimationFrame 功能,该功能并非所有浏览器都支持,并且有几个不同的前缀,具体取决于在您正在使用的浏览器上.在这种情况下,您可以像这样轻松检测和回退:

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) 特征检测

现在,来到真正的问题:如果你想检测对 ES6 的支持,你将无法像我上面说的那样表现,因为 ES6 的相关范围features 基于新的语法和私有词,如果在 ES5 中使用会抛出 SyntaxError,这意味着 编写一个包含 ES5 和 ES6 的脚本是不可能!

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 it contains illegal syntax.
} else {
    var bar = function(arg) { return arg; }
}

现在,由于您不能在同一个脚本中同时有条件地检查和执行 ES6,您必须编写两个不同的脚本:一个只使用 ES5,另一个包含 ES6 特性.使用两个不同的脚本,您将能够导入 ES6 中的一个,前提是它受支持,并且不会导致 SyntaxErrors 被抛出.

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 脚本中使用这些特性:

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

  • 新的Symbol 对象
  • 使用 class 关键字构建的类<​​/li>
  • 箭头((...)=>{...})函数
  • The new Symbol objects
  • Classes built with the class keyword
  • Arrow ((...)=>{...}) functions

注意:新引入语法的特征检测(如箭头函数)只能使用 eval() 函数 或其他等价物(例如 Function()),因为编写无效的语法会在脚本执行之前停止脚本.这也是你不能使用 if 语句检测类和箭头函数的原因:这些特性是关于关键字和语法的,所以一个 eval(...) 包裹在里面try {...} catch (e) {...} 块可以正常工作.

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 标记:

  • HTML Markup:

<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 脚本时并不是最佳实践.我会给你一些关于这个话题的背景知识,只是不要把我的话当作随意的个人意见".

    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".

    引自 MDN 文档 [link]:

    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.

    [...] 您是否正在尝试检查特定功能是否存在?您的站点需要使用某些浏览器尚不支持的特定 Web 功能,并且您希望将这些用户发送到具有较少功能但您知道可以使用的旧网站.这是使用用户代理检测的最糟糕的原因,因为很可能最终所有其他浏览器都会迎头赶上.在这种情况下,您应该尽量避免使用用户代理嗅探,并改为进行特征检测.

    [...] 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.

    此外,您是说您使用 navigator.appVersion,但请考虑使用另一种方法,因为该方法与许多其他导航器属性一起不推荐使用,并且并不总是像你想的那样.

    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.

    因此,引用 MDN 文档 [link] 再次:

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

    已弃用:此功能已从 Web 标准中删除.虽然一些浏览器可能仍然支持它,但它正在被删除.不要在旧项目或新项目中使用它.使用它的页面或网络应用程序可能随时中断.

    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.

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

    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天全站免登陆