5

Así ECMAScript 5 introduce algunas incompatibilidades con ECMAScript 3.¿Cómo asegurarse de que los programas de ES3 se ejecuten en un motor ES5?


Ejemplo:

Manyarticles haber sido escrito indicando que es posible this === null || this === undefineden modo estricto ES5:

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

Pero, ¿qué the standard realmente indica es que los motores de ES5 también permiten que este en modo no estricto:

15.3.4.3 ... El valor thisArg se pasa sin modificaciones como el valor this. Esto es un cambio de la Edición 3, donde undefined o null thisArg se reemplaza con el objeto global y ToObject se aplica a todos los demás valores y ese resultado se pasa como el valor this.

Actualmente, IE9 es el único navegador que realmente implementa ES5 de esta manera, y resulta que esto puede break current scripts. Estupendo.


Annix E del ES5 spec enumera docenas de otras incompatibilidades.

Entonces, ¿cuál es la mejor manera de asegurarse de que nuestros scripts de ES3 bien probados continuarán funcionando sin problemas? ¿Algún tipo de prueba automatizada? ¿Tendremos que probarlo todo de forma manual?

Respuesta

4

Suite de prueba automatizada es sin duda una buena idea.

Desde más y más implementaciones implementan ES5 ahora, ejecutar el banco de pruebas para su secuencia de comandos/biblioteca/aplicación en los navegadores más nuevos es una buena forma de garantizar la compatibilidad.

Tengo un ES5 compatibility table, que enumera el nivel de compatibilidad de algunas de las implementaciones más populares. No es exhaustivo, pero muestra la dirección general: el último IE, WebKit, Chrome y Firefox tienen un buen soporte para ES5. Para una prueba de conformidad completa, siempre puede ejecutar el conjunto de pruebas oficial de ES5 (que tengo en línea para mayor comodidad right here).

Si no existe un conjunto de pruebas (que realmente debería existir, ya que es muy útil por otros motivos), puede ejecutar script/biblioteca/aplicación en una de las implementaciones más recientes (conforme a ES5) y ver qué funciona y lo que falla

Consultar Annex E es otra manera de hacerlo. Tenga en cuenta que, aunque la lista parece bastante grande, no es tan mala como parece. Uno de los objetivos de ES5 era hacer la transición de ES3 más o menos indolora, moviendo cambios más radicales en el ámbito de opt-in modo estricto.

Es probable que muchos cambios de compatibilidad de esa lista pasen desapercibidos. Tomemos como ejemplo, cambie en 15.1.1, donde global undefined, NaN y ahora son de solo lectura.Teniendo en cuenta que las aplicaciones en buen estado no reasignan estas propiedades globales, excepto por error, este cambio es más un "receptor de error" agradable en lugar de "interruptor de aplicación".

Otro cambio liekly inocente está en 15.10.2.12, en clase de caracteres de espacio en blanco (\s) ahora también coincide con < lista de materiales> (U+FEFF) carácter. Teniendo en cuenta all the deviations en las implementaciones actuales (incluso en lo que respecta a ES3), es probable que este cambio pase desapercibido en la mayoría de las aplicaciones.

Sin embargo, también hay cambios más peligrosos, como el de parseInt y la forma en que ya no se trata a las cadenas que comienzan con 0 como valores octales. parseInt('010') ya no debería producir 8 (aunque algunas implementaciones eligen deliberately violate that behavior). Y aún así, confiar en parseInt sin un segundo argumento "raíz" nunca fue una buena práctica. Entonces, si su aplicación siempre especifica radix, no hay nada de qué preocuparse.

Consulte el Anexo E, pruebe su script en las implementaciones más nuevas (preferiblemente, varias) y siga las mejores prácticas. Esa es una buena forma de garantizar la compatibilidad.

+0

Su conjunto de pruebas es realmente bueno. Sin embargo, me temo que no ayudará con mi situación particular. Básicamente, mi compañía necesita asegurarse de que nuestros scripts heredados no causen ningún problema en las instalaciones de nuestros clientes. Estamos hablando de cientos y cientos de scripts aquí, y comprobar manualmente cada funcionalidad parece un gran dolor. ("¿Pruebas unitarias? ¿Qué es eso?") Actualmente, me temo que simplemente estamos esperando informes de errores. – user123444555621

+0

¿Qué tal si ejecuta scripts a través de JSLint? Uno por uno, poco a poco.Es posible que JSLint no cubra todos los cambios sensibles a compat, pero sin duda lo acercará. Advertirá sobre parseInt sin radix y sobre los nombres de propiedad como palabras clave (por ejemplo, '({if: 1})') y otros. – kangax

+0

Lamentablemente, JSLint informará miles de errores y, ocasionalmente, se negará a continuar (por ejemplo, al presionar 'void') aunque los scripts funcionen correctamente en ES3. De hecho, he hecho algunos mods JSLint en el pasado, y estoy pensando en agregar algunas cosas de ES5 también. Sin embargo, algunas de las incompatibilidades (7.8.5/1, 10.4.2, 10.6/2, 15.3.4.3, 15.3.4.4, 15.10.2.12) son muy difíciles de encontrar en el momento del análisis. – user123444555621

6

Para el registro, la interpretación del cuestionario de ES5 15.3.4.3 es incorrecta. Cualquier llamada a una función no estricta en ES5 debe ser observablemente la misma que en ES3. El objeto global aún se pasa a cualquier función no estricta que se invoca con nulo o indefinido como este valor.

la pieza que falta del análisis es 10.4.3 "Introducción de Código de función":

se realizan los siguientes pasos cuando el control entra en el contexto de ejecución para código de función contenido en un objeto de función F, una persona que llama proporciona thisArg, y una persona que llama proporciona argumentsList:

  1. Si el f el código de la unción es un código estricto, establezca ThisBinding en thisArg.
  2. Porque si thisArg es nula o indefinido, establecer el ThisBinding al objeto global.
  3. ...

ES3 especificó que la persona que llama era responsable de la sustitución del objeto global para un nulo o no definido este valor. ES5 especifica que el destinatario tiene esa responsabilidad (si no es una función de modo estricto). Para el código no estricto, esta no es una diferencia observable. El cambio de especificación solo hace una diferencia cuando el llamado es una función estricta.

+0

Typo: "indefinido como el valor" –

+0

@ AxelRauschmayer-ES5 tiene que funcionar de esa manera porque la persona que llama no necesariamente sabe si el destinatario está en modo estricto o no. Así que pasar el * thisArg * de la llamada y dejar que el destinatario lo resuelva tiene sentido. :-) – RobG

Cuestiones relacionadas