5

Così ECMAScript 5 introduce alcune incompatibilità con ECMAScript 3.Come assicurarsi che i programmi ES3 funzioneranno in un motore ES5?


Esempio:

Manyarticles sono stati scritti affermando che this === null || this === undefined è possibile in ES5 modalità rigorosa:

"use strict"; 
(function() { 
    alert(this); // null 
}).call(null); 

Ma, che cosa the standarddavvero suggerisce è che i motori ES5 permettono anche questo in modalità non rigorosa:

15.3.4.3 ... Il valore thisArg viene passato senza modifiche come valore this. Si tratta di una modifica dall'edizione 3, in cui un oggetto undefined o null viene sostituito con l'oggetto globale e ToObject viene applicato a tutti gli altri valori e tale risultato viene passato come valore this.

Attualmente, IE9 è l'unico browser che implementa ES5 in questo modo e risulta che ciò potrebbe essere break current scripts. Grande.


Annix E di ES5 spec elenca decine di altre incompatibilità.

Quindi qual è il modo migliore per assicurarsi che i nostri ben collaudati script ES3 continuino a funzionare in modo impeccabile? Una specie di suite di test automatizzata? Dovremo testarlo tutto manualmente?

risposta

4

La suite di test automatizzata è sicuramente una buona idea.

Dal sempre più implementazioni implementano ES5 ora, l'esecuzione della suite di test per il tuo script/libreria/applicazione nei browser più recenti è un buon modo per garantire la compatibilità.

Ho un ES5 compatibility table, che elenca il livello di supporto di alcune delle implementazioni più popolari. Non è esaustivo, ma mostra una direzione generale: l'ultimo IE, WebKit, Chrome e Firefox hanno tutti un buon supporto ES5. Per un test di conformità completo, è sempre possibile eseguire la suite di test ES5 ufficiale (che ho online per comodità right here).

Se non c'è una suite di test (che dovrebbe esistere realmente, poiché è molto utile per pochi altri motivi), è sufficiente eseguire script/libreria/applicazione in una delle implementazioni più recenti (conformi a ES5) e vedere cosa funziona e ciò che fallisce.

Consulenza Annex E è un altro modo per andare. Nota che anche se la lista sembra abbastanza grande, non è così male come sembra. Uno degli obiettivi di ES5 era rendere la transizione da ES3 più o meno indolore, spostando cambiamenti più radicali nel regno di modalità rigorosa di attivazione.

È probabile che molte modifiche di compatibilità da tale elenco passino inosservate. Prendiamo ad esempio, modificare in 15.1.1, dove globale undefined, NaN e Infinity sono ora di sola lettura.Considerando che le applicazioni sensate non riassegnano queste proprietà globali - ad eccezione di per errore - questa modifica è più di un piacevole "catcher di errori" piuttosto che di "interruzione di app".

Un altro cambiamento liekly innocente è in 15.10.2.12, dove la classe carattere di spaziatura (\s) ora corrisponde anche < BOM> (U+FEFF) carattere. Considerando all the deviations nelle implementazioni correnti (anche per quanto riguarda ES3), è probabile che questo cambiamento passi inosservato nella maggior parte delle applicazioni.

Tuttavia, ci sono anche cambiamenti più pericolose, come quella in parseInt e come essa non tratta le stringhe che iniziano con 0 come valori ottali. parseInt('010') non dovrebbe più produrre 8 (sebbene alcune implementazioni abbiano scelto deliberately violate that behavior). E ancora, affidarsi a parseInt senza un secondo argomento "radix" non è mai stato una buona pratica. Quindi se la tua applicazione specifica sempre la radice, non c'è nulla di cui preoccuparsi.

Quindi consultare l'Allegato E, testare lo script nelle implementazioni più recenti (preferibilmente multiple) e seguire le best practice. Questo è un buon modo per garantire la compatibilità.

+0

La tua suite di test è davvero buona. Tuttavia, temo che non aiuti con la mia situazione particolare. Fondamentalmente, la mia azienda deve assicurarsi che i nostri script legacy non causino problemi nelle installazioni dei nostri clienti. Stiamo parlando di centinaia e centinaia di script qui, e il controllo manuale di ogni singola funzionalità sembra molto doloroso. ("Test unitari? Che cos'è?") Attualmente, temo che stiamo semplicemente aspettando segnalazioni di bug. – user123444555621

+0

Che ne dici di eseguire gli script tramite JSLint? Uno per uno, a poco a poco.JSLint potrebbe non coprire tutte le modifiche compat-sensitive, ma sicuramente ti farà avvicinare. Avverrà su parseInt w/o radix e sui nomi di proprietà come parole chiave (ad es. '({If: 1})'), e altri. – kangax

+0

Sfortunatamente, JSLint segnalerà migliaia di errori e occasionalmente si rifiuterà di continuare (ad es. Quando si preme 'void') anche se gli script funzionano bene in ES3. In effetti, ho realizzato alcune mod JSLint in passato, e sto pensando di aggiungere anche alcune cose di ES5. Tuttavia, alcune delle incompatibilità (7.8.5/1, 10.4.2, 10.6/2, 15.3.4.3, 15.3.4.4, 15.10.2.12) sono molto difficili da trovare in fase di analisi. – user123444555621

6

Per la cronaca, l'interpretazione dell'interrogante di ES5 15.3.4.3 non è corretta. Qualsiasi chiamata a una funzione non rigida in ES5 dovrebbe essere osservabile come in ES3. L'oggetto globale è ancora passato in qualsiasi funzione non rigida chiamata con valore null o undefined come questo valore.

Il pezzo mancante dell'analisi è 10.4.3 "Inserimento Codice funzione":

vengono eseguite le seguenti operazioni quando il controllo entra nel contesto di esecuzione codice funzione contenuta in un oggetto funzione F, un chiamante fornito thisArg, e un chiamante fornito argumentsList:

  1. Se la f il codice unction è un codice rigoroso, imposta ThisBinding su thisArg.
  2. Altrimenti se thisArg è nullo o indefinito, impostare il ThisBinding all'oggetto globale.
  3. ...

ES3 ha precisato che il chiamante è stato responsabile per la sostituzione dell'oggetto globale per un null o undefined questo valore. ES5 specifica che il destinatario ha quella responsabilità (se non è una funzione in modalità rigorosa). Per il codice non severo questa non è una differenza osservabile. La modifica delle specifiche fa la differenza solo quando il callee è una funzione rigorosa.

+0

Typo: "non definito come il valore" –

+0

@ AxelRauschmayer-ES5 deve funzionare in questo modo perché il chiamante non sa necessariamente se il destinatario si trova in modalità rigorosa o meno. Quindi passare il * thisArg * dalla chiamata e lasciare che il callee lo risolva ha senso. :-) – RobG

Problemi correlati