草庐IT

Javascript ES6 跨浏览器检测

coder 2023-07-04 原文

如何找出浏览器的 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()) {
    // Use SpecialObject and specialFunction
} else {
    // You cannot use them :(
}

为什么特征检测比浏览器/引擎检测更好?

在大多数情况下,有多种原因使特征检测成为最佳选择:
  • 您不必依赖浏览器的版本、引擎或细节,也不必使用难以实现且非常狡猾的启发式方法来检测它们。
  • 您不会陷入有关浏览器/引擎规范检测的错误中。
  • 您不必担心特定于浏览器的功能:例如 WebKit浏览器的规范与其他浏览器不同。
  • 您可以确定,一旦检测到某个功能,您就可以使用它。

  • 这些是恕我直言使特征检测成为最佳方法的主要原因。

    特征检测+回退

    使用时特征检测 ,当您不确定可以/不能使用哪些功能时,这是一种非常聪明的工作方式,包含在 中。几个特征检测和随之而来的对更基本方法的回退 (甚至从头开始创建这些方法)以防您要使用的功能不受支持。

    具有回退功能的特征检测的简单示例可以应用于 window.requestAnimationFrame功能,并非所有浏览器都支持该功能,并且根据您使用的浏览器有几个不同的前缀。在这种情况下,您可以像这样轻松检测和回退:
    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 特性基于新的语法和私有(private)词,并且会抛出 SyntaxError如果在 ES5 中使用 ,这意味着 编写同时包含 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 it contains illegal syntax.
    } else {
        var bar = function(arg) { return arg; }
    }
    

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

    ES6 检测和条件执行示例

    现在让我们做一个更相关的例子,假设你想在你的 ES6 脚本中使用这些特性:
  • 新款Symbol对象
  • 使用 class 构建的类关键字
  • 箭头 ( (...)=>{...} ) 函数

  • 注意: 新引入语法的特征检测 (如箭头函数)只能使用 eval() 来完成功能或其他等价物(例如 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 文档 [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.



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

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

    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 跨浏览器检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29046635/

    有关Javascript ES6 跨浏览器检测的更多相关文章

    1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

      我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

    2. ruby - 在 Ruby 中用键盘诅咒数组浏览 - 2

      我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作

    3. ruby-on-rails - 浏览 Ruby 源代码 - 2

      我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

    4. ruby - 检测由 RSpec、Ruby 运行的代码 - 2

      我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题

    5. ruby - 使用 Ruby Daemons gem 检测停止 - 2

      我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe

    6. ruby - 强制浏览器下载文件而不是打开文件 - 2

      我要下载http://foobar.com/song.mp3作为song.mp3,而不是让Chrome在其native中打开它浏览器中的播放器。我怎样才能做到这一点? 最佳答案 您只需要确保发送这些header:Content-Disposition:attachment;filename=song.mp3;Content-Type:application/octet-streamContent-Transfer-Encoding:binarysend_file方法为您完成:get'/:file'do|file|file=File.

    7. ruby - 404 未找到,但可以从网络浏览器正常访问 - 2

      我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT

    8. ruby - 如何在 watir 测试套件结束时关闭浏览器? - 2

      使用ruby​​的watir测试网络应用程序时,浏览器最后会保持打开状态。网上的一些建议是,要进行真正的单元测试,您应该在每次测试时(在拆卸调用中)打开和关闭浏览器,但这很慢而且毫无意义。或者他们做这样的事情:defself.suites=superdefs.afterClass#Closebrowserenddefs.run(*args)superafterClassendsend但这会导致摘要输出不再显示(诸如“100次测试、100次断言、0次失败、0次错误”之类的内容仍应显示)。我怎样才能让ruby​​或watir在我的测试结束时关闭浏览器? 最佳答案

    9. ruby - Ruby 脚本如何检测到它正在 irb 中运行? - 2

      我有一个定义类的Ruby脚本。我希望脚本执行语句BoolParser.generate:file_base=>'bool_parser'仅当脚本作为可执行文件被调用时,而不是当它被irbrequire(或通过-r在命令行上传递)时。我可以用什么来包装上面的语句,以防止它在我的Ruby文件加载时执行? 最佳答案 条件$0==__FILE__...!/usr/bin/ruby1.8classBoolParserdefself.generate(args)p['BoolParser.generate',args]endendif$0==_

    10. Ruby 无法检测字符串中的换行符 - 2

      我有以下字符串,我想检测那里的换行符。但是Ruby的字符串方法include?检测不到它。我正在运行Ruby1.9.2p290。我哪里出错了?"/'ædres/\nYour".include?('\n')=>false 最佳答案 \n需要在双引号内,否则无法转义。>>"\n".include?'\n'=>false>>"\n".include?"\n"=>true 关于Ruby无法检测字符串中的换行符,我们在StackOverflow上找到一个类似的问题: h

    随机推荐