Rilevazione cross-browser Javascript ES6

Come posso scoprire la versione del motore Javascript del browser e il supporto per ECMAScript 6?

Sto usando navigator.appVersion solo per conoscere la versione del browser, ma non la versione del motore.

Rilevamento di funzionalità

Ti suggerisco di utilizzare il rilevamento delle funzionalità invece di rilevare il motore del browser con metodi euristici. Per fare questo puoi semplicemente racchiudere del codice all’interno di un’istruzione try {..} catch (e) {...} , o usare alcune istruzioni if (...) .

Per esempio:

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

Perché il rilevamento di funzionalità è migliore del rilevamento di browser / motore?

Esistono diversi motivi che rendono, nella maggior parte dei casi, il rilevamento delle funzionalità l’opzione migliore:

  • Non devi fare affidamento sulla versione, il motore o le specifiche del browser, né rilevarli utilizzando metodi euristici che sono difficili da implementare.

  • Non ti imbatterai in errori relativi al rilevamento delle specifiche del browser / motore.

  • Non devi preoccuparti delle funzionalità specifiche del browser: ad esempio i browser WebKit hanno specifiche diverse da quelle degli altri.

  • Puoi star sicuro che, una volta rilevata una funzione, sarai in grado di usarla.

Queste sono le ragioni principali per cui IMHO rende l’individuazione delle funzionalità l’approccio migliore.

Rilevamento di funzioni + fallback

Quando si utilizza il rilevamento di funzionalità , un modo piuttosto intelligente di funzionare quando non si è sicuri di quali funzionalità è ansible / non utilizzare consiste in diverse rilevazioni di feature e conseguenti fallback a metodi più basilari (o addirittura alla creazione di questi metodi da zero) nel caso in cui le funzionalità vuoi usare non sono supportati.

Un semplice esempio di rilevamento di funzionalità con fallback può essere applicato alla funzione window.requestAnimationFrame , che non è supportata da tutti i browser e ha diversi prefissi diversi a seconda del browser su cui stai lavorando. In questo caso, puoi facilmente rilevare e fallback in questo modo:

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

Rilevamento delle funzioni di ECMAScript 6 (Harmony)

Ora, arrivando al vero problema : se vuoi rilevare il supporto per ES6, non sarai in grado di comportarti come ho detto sopra, perché una gamma rilevante di funzionalità di ES6 si basa su nuove syntax e parole private e a SyntaxError se usato in ES5 , il che significa che scrivere uno script che contenga sia ES5 che ES6 è imansible!

Ecco un esempio per dimostrare questo problema; il frammento di seguito non funzionerà e verrà bloccato prima dell’esecuzione perché contiene syntax non consentita.

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

Ora, dal momento che non è ansible controllare ed eseguire ES6 condizionatamente nello stesso script, è necessario scrivere due script diversi : uno che utilizza solo ES5 e un altro che include le funzionalità ES6. Con due diversi script sarete in grado di importare l’ES6 solo se è supportato e senza causare il lancio di SyntaxErrors .

Rilevazione ES6 ed esempio di esecuzione condizionale

Ora facciamo un esempio più riconoscibile e supponiamo che vogliate utilizzare queste funzionalità nel vostro script ES6:

  • I nuovi oggetti Symbol
  • Classi costruite con la parola chiave class
  • Arrow ( (...)=>{...} ) funzioni

NOTA: la funzione di rilevamento delle syntax introdotte di recente (come le funzioni freccia) può essere eseguita solo utilizzando la eval() o altri equivalenti (es. Function() ), poiché la scrittura della syntax non valida interromperà lo script prima della sua esecuzione. Questo è anche il motivo per cui non è ansible utilizzare le istruzioni per rilevare classi e funzioni di freccia: queste caratteristiche riguardano le parole chiave e la syntax, quindi una eval(...) racchiusa all’interno di una try {...} catch (e) {...} blocco funzionerà correttamente.

Quindi, arrivando al codice reale:

  • Markup HTML:

             
  • Codice nello script 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 :( } 
  • Codice in 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! 

Rilevazione browser / motore

Come ho detto sopra, il rilevamento di browser e motori non è la procedura migliore quando si programma uno script JavaScript. Ti darò qualche informazione su questo argomento, giusto per non lasciare le mie parole come “opinioni personali a caso”.

Citando dalla documentazione MDN [ collegamento ]:

Quando si considera l’utilizzo della stringa dell’agente utente per rilevare quale browser viene utilizzato, il primo passo è cercare di evitarlo se ansible. Inizia cercando di identificare il motivo per cui vuoi farlo.

[…] Stai cercando di verificare l’esistenza di una funzione specifica? Il tuo sito deve utilizzare una funzionalità Web specifica che alcuni browser non supportano ancora e desideri inviare quegli utenti a un sito Web precedente con meno funzioni ma che sai funzionerà. Questa è la peggiore ragione per usare il rilevamento di user-agent, perché le probabilità sono alla fine tutte le altre navigazioni raggiungeranno. Dovresti fare del tuo meglio per evitare di utilizzare lo sniffing di user-agent in questo scenario e invece di eseguire il rilevamento delle funzionalità .

Inoltre, stai dicendo che usi navigator.appVersion , ma considera di utilizzare un altro approccio, perché quello, insieme a molte altre proprietà del navigatore, è deprecato e non si comporta sempre come pensi.

Quindi, citando di nuovo dalla documentazione MDN [ link ]:

Obsoleto : questa funzione è stata rimossa dagli standard Web. Sebbene alcuni browser possano ancora supportarlo, è in fase di rilascio. Non usarlo in progetti vecchi o nuovi. Le pagine o le app Web che lo utilizzano potrebbero interrompersi in qualsiasi momento.

Nota: non fare affidamento su questa proprietà per restituire la versione corretta del browser. Nei browser basati su Gecko (come Firefox) e WebKit (come Chrome e Safari) il valore restituito inizia con “5.0” seguito dalle informazioni sulla piattaforma. In Opera 10 e versioni successive, la versione restituita non corrisponde nemmeno alla versione attuale del browser.

I fornitori di browser che supportano i moduli ES6 ora forniscono un modo semplice per eseguire il rilevamento delle funzionalità:

 ...     ... 

Lo script con l’attributo nomodule non sarà eccitato dai browser che supportano

Puoi anche inserire lo script in questo modo:

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

Come ha detto Marco Bonelli, il modo migliore per rilevare la syntax del linguaggio ECMAScript 6 è usare eval (); . Se la chiamata non genera un errore, sono supportate tutte le altre funzionalità, ma raccomando Function (); .

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

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

  1. Rileva dispositivoPixelRatio che è una proprietà speciale in WebKit .
  2. Rileva l’attrezzo della funzione javaEnabled.
 (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); } })() 

Per ora non esiste un modo preciso per rilevare ES6, ma se si testano le sue funzionalità nel browser corrente, è ansible determinare se il motore è ES6. La mia libreria esx rileva la versione di ECMAScript eseguendo test di syntax e controllo dei metodi. Per sapere che può rilevare ECMAScript 3, 5, 6 e 7 (ES7 non testato, ma dovrebbe funzionare), se nessun test ECMAScript corrisponde, dà null come risultato.

Esempio usando la mia biblioteca:

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

Inserisci il codice di syntax incompatibile, ad esempio contenente le funzioni freccia, nel proprio blocco di script e aggiungilo in polyfill con codice di syntax compatibile.