developer tip

Javascript ES6 브라우저 간 감지

optionbox 2020. 12. 4. 08:06
반응형

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()) {
    // 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에 대한 지원을 감지하려면 위에서 말한 것처럼 행동 할 수 없습니다. ES6 기능의 관련 범위는 새로운 구문과 비공개 단어를 기반으로SyntaxError 하기 때문입니다 . a 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 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!
    

브라우저 / 엔진 감지

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.


Browser vendors that support ES6 modules now provide an easy way to do feature detection:

...
<head>
  <script nomodule>window.nomodules = true;</script>
  <script>console.log(window.nomodules)</script>
</head>
...

The script with the nomodule attribute will not be excuted by browsers which support <script type="module" ...>

You can also inject the script like this:

const script = document.createElement('script');
script.setAttribute('nomodule', '');
script.innerHTML = 'window.nomodules = true;';
document.head.insertBefore(script, document.head.firstChild);
script.remove();

As Marco Bonelli said, the best way to detect ECMAScript 6 language syntax is to use eval();. If the call does not throw an error, "all other" features are supported, but I recommend Function();.

function isES6()
{
    try
    {
        Function("() => {};"); return true;
    }
    catch(exception)
    {
        return false;
    }
}

demo: https://jsfiddle.net/uma4Loq7/


  1. Detect devicePixelRatio which is a special property in WebKit.
  2. Detect javaEnabled function's implement.

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

})()


For now there's not a exact way to detect ES6, but if you test its features in the current browser, you can determine if the engine is ES6. My esx library detects the ECMAScript version by doing syntax tests and methods check. For know it can detect ECMAScript 3, 5, 6 and 7 (ES7 not tested, but should work), if no ECMAScript test matched, it gives null as result.

Example using my library:

if (esx.detectVersion() >= 6) {
    /* We're in ES6 or above */
}

Put the incompatible syntax code, such as containing arrow functions, in it's own script block and polyfill it with compatible syntax code.

<script>
        // This script block should not compile on incompatible browsers, 
        // leaving the function name undefined.
        // It can then be polyfilled with a function containing compatible syntax code.
        function fame() {
            /* incompatible syntax code such as arrow functions */
        }
</script>

<script>
    if (typeof fame !== "function") {
        // alert("polyfill: fame");
        function fame() {
            /* compatible syntax code */
        }
    }
</script>

<script>
    // main code
    fame();
</script>

참고URL : https://stackoverflow.com/questions/29046635/javascript-es6-cross-browser-detection

반응형