1. ホーム
  2. javascript

[解決済み] Javascript ES6によるクロスブラウザ検出

2023-07-10 01:03:17

質問

ブラウザの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 ブラウザは他のブラウザと異なる仕様を持っています。

  • 機能が検出されれば、それを使用することができることを確認できます。

これらが、IMHO が機能検出を最良のアプローチとする主な理由です。

機能検出 + フォールバック

を使う場合 特徴検出 で構成される、どの機能を使えるか/使えないかわからないときに、かなりスマートな方法で作業することができます。 複数の機能検出とその結果である フォールバック をより基本的なメソッドに (あるいはゼロからこれらのメソッドを作成する)使用したい機能がサポートされていない場合に備えて。

の簡単な例です。 フォールバックによる機能検出 を適用することができます。 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 のサポートを検出したい場合、私が上で言ったような動作はできません。 を投げてしまうからです。 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 it contains illegal syntax.
} else {
    var bar = function(arg) { return arg; }
}

さて、ES6のチェックと条件付き実行の両方を同じスクリプトで行うことはできないので の2つのスクリプトを書く必要があります。 を書く必要があります。2つのスクリプトを使えば 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ドキュメントから引用 [... リンク ]:

どのブラウザが使用されているかを検出するためにユーザーエージェント文字列を使用することを検討する場合、最初のステップは、可能であればそれを回避しようとすることです。なぜそうしたいのかを特定することから始めてください。

[...] 特定の機能の存在を確認しようとしているのでしょうか? あなたのサイトでは、一部のブラウザがまだサポートしていない特定の Web 機能を使用する必要があり、それらのユーザーを、機能は少ないが動作することが分かっている古い Web サイトに送りたい場合です。これは、ユーザーエージェント検出を使う理由として最も不適当なものです。このようなシナリオでは、ユーザエージェント検出を使用しないように最善を尽くさなければなりません。 機能検出を行います。 .

また、あなたが使っているのは navigator.appVersion を使用していると言っていますが、別のアプローチを使用することを検討してください。なぜなら、その1つは、他の多くのナビゲータ・プロパティと一緒で 非推奨 であり、常にあなたが考えているように動作するわけではありません。

ということで、MDNドキュメントから引用すると、[... リンク ]をもう一度。

非推奨 : この機能はウェブ標準から削除されました。いくつかのブラウザはまだサポートしているかもしれませんが、廃止される方向にあります。古いプロジェクトでも新しいプロジェクトでも、この機能を使わないでください。これを使用したページまたは Web アプリは、いつでも壊れる可能性があります。

注意してください。 正しいブラウザのバージョンを返すために、このプロパティに依存しないでください。Gecko ベースのブラウザ (Firefox など) および WebKit ベースのブラウザ (Chrome や Safari など) では、返される値は "5.0" で始まり、プラットフォーム情報が続きます。Opera 10 およびそれ以降のバージョンでは、返されるバージョンは実際のブラウザのバージョンとも一致しません。