¿Por qué se requiere JavaScript en modo estricto?

El modo estricto es una parte importante del JavaScript moderno. Es este modo el que permite a los desarrolladores usar una sintaxis más limitada que la estándar.

La semántica del modo estricto es diferente del modo no estricto tradicional, que a veces se denomina "modo descuidado". En este modo, las reglas de sintaxis del lenguaje no son tan estrictas, y cuando ocurren algunos errores, el sistema no notifica al usuario sobre ellos. Es decir, los errores se pueden ignorar y el código en el que se realizan se puede ejecutar más. Esto puede conducir a resultados inesperados de ejecución de código.



El modo estricto introduce algunos cambios en la semántica de JavaScript. Evita que el sistema haga la vista gorda ante los errores al lanzar las excepciones apropiadas. Esto hace que la ejecución del programa se detenga.

El modo estricto, además, ayuda a escribir programas en los que no hay defectos que impidan que los motores JS optimicen el código. Además, en este modo está prohibido usar elementos de sintaxis que puedan tener un significado especial en futuras versiones del lenguaje.

Características del uso del modo estricto


El modo estricto se puede aplicar a funciones individuales o a un script completo. No se puede aplicar solo a instrucciones individuales o a bloques de código encerrados entre llaves. Para usar el modo estricto a nivel de toda la secuencia de comandos, al comienzo del archivo, antes de cualquier otro comando, debe poner el "use strict" o 'use strict' construcción 'use strict' .

Si el proyecto tiene algunos scripts que no usan el modo estricto y otros que usan este modo, puede suceder que estos scripts se fusionen.

Esto conducirá al hecho de que el código que no está destinado a ejecutarse en modo estricto estará en tal estado cuando el sistema intente ejecutarlo en modo estricto. También es posible lo contrario: el código escrito para el modo estricto caerá en el modo no estricto. Por lo tanto, es mejor no mezclar scripts "estrictos" y "no estrictos".

Como ya se mencionó, el modo estricto se puede aplicar a funciones individuales. Para hacer esto, la construcción "use strict" o 'use strict' debe colocarse en la parte superior del cuerpo de la función, antes que cualquier otro comando. El modo estricto con este enfoque se aplica a todo lo que se coloca en el cuerpo de la función, incluidas las funciones anidadas.

Por ejemplo:

 const strictFunction = ()=>{  'use strict';  const nestedFunction = ()=>{    //        } } 

En los módulos JavaScript que aparecieron en el estándar ES2015, el modo estricto está habilitado de forma predeterminada. Por lo tanto, cuando trabaje con ellos, no necesita incluirlo explícitamente.

Cambios introducidos en el código JS por modo estricto


El modo estricto afecta tanto la sintaxis del código como el comportamiento del código durante la ejecución del programa. Los errores en el código se convierten en excepciones. El hecho de que en modo silencioso se bloquee silenciosamente en modo estricto provoca un mensaje de error. Esto es similar a cómo el sistema responde a los errores de sintaxis en modo lax. En modo estricto, el trabajo con variables se simplifica, el uso de la función eval y el objeto de arguments están estrictamente regulados, y el trabajo con construcciones que se pueden implementar en futuras versiones del lenguaje se simplifica.

▍ Convertir errores silenciosos en excepciones


Los errores silenciosos se convierten en modo estricto a excepciones. En modo laxo, el sistema no responde explícitamente a tales errores. En modo estricto, la presencia de tales errores conduce a la inoperancia del código.

Entonces, gracias a esto, es difícil cometer el error de declarar accidentalmente una variable global, ya que las variables y constantes en modo estricto no pueden declararse sin usar las directivas var , let o const . Como resultado, la creación de variables sin estas directivas conducirá a la inoperancia del programa. Por ejemplo, intentar ejecutar el siguiente código arrojará una excepción ReferenceError :

 'use strict'; badVariable = 1; 

Dicho código no se puede ejecutar en modo estricto, ya que si el modo estricto se desactivara, crearía la variable global badVariable . El modo estricto protege al programador de la creación inadvertida de variables globales.

Un intento de ejecutar cualquier código que, en modo normal, simplemente no funciona, ahora arroja una excepción. Se considera que los errores son construcciones sintácticas incorrectas que simplemente se ignoraron en modo laxo.

Entonces, por ejemplo, en modo estricto, no puede realizar operaciones de asignación de valores en entidades de solo lectura como arguments , NaN o eval .

En modo estricto, se generará una excepción, por ejemplo, en los siguientes casos:

  • un intento de asignar un valor a una propiedad de solo lectura, como algún tipo de propiedad global regrabable;
  • un intento de escribir un valor en una propiedad que solo tiene un captador;
  • Un intento de escribir algo en una propiedad de un objeto no extensible.

Aquí hay ejemplos de construcciones de sintaxis que conducen a excepciones de modo estricto:

 'use strict'; let undefined = 5; let Infinity = 5; let obj = {}; Object.defineProperty(obj, 'foo', { value: 1, writable: false }); obj.foo = 1 let obj2 = { get foo() { return 17; } }; obj2.foo = 2 let fixedObj = {}; Object.preventExtensions(fixedObj); fixed.bar= 1; 

Intentar ejecutar dichos fragmentos de código en modo estricto generará una excepción TypeError . Por ejemplo, undefined e Infinity son entidades globales cuyos valores no se pueden sobrescribir, y la propiedad foo del objeto obj no admite la reescritura. La propiedad foo de obj2 solo tiene un captador. El objeto fixedObj hace no extensible utilizando el método Object.preventExtensions .

Un intento de eliminar una TypeError no TypeError también dará como resultado TypeError :

 'use strict'; delete Array.prototype 

El modo estricto prohíbe asignar propiedades con el mismo nombre a un objeto. Como resultado, un intento de ejecutar el siguiente código dará como resultado un error de sintaxis:

 'use strict'; let o = { a: 1, a: 2 }; 

El modo estricto requiere que los nombres de los parámetros de la función sean únicos. En modo no estricto, si, por ejemplo, dos parámetros de función tienen el mismo nombre one , entonces, al pasar la función de argumento, el valor del parámetro será el que cayó en el argumento declarado en último lugar.

En modo estricto, los parámetros de funciones con el mismo nombre están prohibidos. Como resultado, un intento de ejecutar el siguiente código dará como resultado un error de sintaxis:

 'use strict'; const multiply = (x, x, y) => x*x*y; 

En modo estricto, no puede usar la notación octal de números, precediendo el número con cero. Esto no está en la especificación, pero esta característica es compatible con los navegadores.

Este estado de cosas confunde a los desarrolladores, obligándolos a creer que el 0 que precede al número simplemente se ignora, sin mucho sentido. En modo estricto, intentar usar un número al principio del cual sea 0 dará como resultado un error de sintaxis.

El modo estricto también prohíbe el uso de construcciones que impiden la optimización. El intérprete, antes de realizar la optimización del código, necesita saber que la variable se almacena exactamente donde, según el intérprete, se almacena. En modo estricto, las cosas que interfieren con las optimizaciones están prohibidas.

Un ejemplo de tal prohibición se refiere a la declaración with . Si usa esta instrucción, esto evita que el intérprete JS descubra a qué variable o qué propiedad nos referimos, ya que es posible que exista una entidad con el mismo nombre tanto fuera como dentro del bloque de la instrucción with .

Supongamos que hay un código como este:

 let x = 1; with (obj) {  x; } 

El intérprete no podrá averiguar si la variable x ubicada dentro del bloque with se refiere a la variable externa x , oa la propiedad obj.x del objeto obj .

Como resultado, no está claro exactamente dónde se ubicará el valor x en la memoria. Para deshacerse de tales ambigüedades, en modo estricto está prohibido el uso de la declaración with . Veamos qué sucede si intentas ejecutar el siguiente código en modo estricto:

 'use strict'; let x = 1; with (obj) {  x; } 

El resultado de este intento será un error de sintaxis.

Incluso en modo estricto, está prohibido declarar variables en el código pasado al método eval .

Por ejemplo, en modo normal, un comando de la forma eval('let x') dará como resultado la declaración de la variable x . Esto permite a los programadores ocultar declaraciones de variables en cadenas, lo que puede conducir a sobrescribir las definiciones de las mismas variables fuera de eval .

Para evitar esto, en modo estricto está prohibido declarar variables en el código pasado como una cadena al método eval .

El modo estricto también prohíbe la eliminación de variables regulares. Como resultado, intentar ejecutar el siguiente código dará como resultado un error de sintaxis:

 'use strict'; let x; delete x; 

▍ Prohibir construcciones de sintaxis incorrectas


En modo estricto, el uso incorrecto de eval y arguments prohibido. Esta es una prohibición de todo tipo de manipulaciones con ellos. Por ejemplo, esto es algo así como asignarles nuevos valores, usando sus nombres como nombres de variables, funciones, parámetros de función.

Aquí hay ejemplos de mal uso de eval y arguments :

 'use strict'; eval = 1; arguments++; arguments--; ++eval; eval--; let obj = { set p(arguments) { } }; let eval; try { } catch (arguments) { } try { } catch (eval) { } function x(eval) { } function arguments() { } let y = function eval() { }; let eval = ()=>{ }; let f = new Function('arguments', "'use strict'; return 1;"); 

En modo estricto, no puede crear alias para el objeto de arguments y establecer nuevos valores de arguments través de estos alias.

En modo normal, si el primer parámetro de la función es a , entonces establecer el valor de a en el código de la función también conduce a un cambio en el valor de los arguments[0] . En modo estricto, los arguments siempre contendrán la lista de argumentos con los que se llamó a la función.

Supongamos que tiene el siguiente código:

 const fn = function(a) {  'use strict';  a = 2;  return [a, arguments[0]]; } console.log(fn(1)) 

La consola obtendrá [2,1] . Esto se debe a que escribir un valor de 2 en a no escribe un valor de 2 en los arguments[0] .

▍ Optimizar el rendimiento


En modo estricto, la propiedad arguments.callee no es compatible. En el modo normal, devuelve el nombre de la función principal de la función cuya propiedad callee del objeto de arguments que estamos examinando.

El soporte para esta propiedad interfiere con las optimizaciones, como las funciones de alineación, ya que el uso de arguments.callee requiere la disponibilidad de una referencia a una función no incrustada al acceder a esta propiedad. En modo estricto, el uso de arguments.callee genera una excepción TypeError .

En modo estricto, this no tiene que ser siempre un objeto. En circunstancias normales, si this función está vinculada, utilizando call , apply o bind , a algo que no es un objeto, a un valor de un tipo primitivo como undefined , null , number o boolean , dicho valor debería ser un objeto.

Si el contexto de this cambia a algo que no es un objeto, un objeto global toma su lugar. Por ejemplo, window . Esto significa que si llama a una función estableciendo this en un valor que no es un objeto, en lugar de este valor, una referencia al objeto global caerá en this .

Considere un ejemplo:

 'use strict'; function fn() {  return this; } console.log(fn() === undefined); console.log(fn.call(2) === 2); console.log(fn.apply(null) === null); console.log(fn.call(undefined) === undefined); console.log(fn.bind(true)() === true); 

Todos los comandos de console.log generarán true , porque en modo estricto el valor de this en la función no se reemplaza automáticamente por una referencia al objeto global si this establece en un valor que no es un objeto.

▍ Cambios relacionados con la seguridad


En modo estricto, no puede hacer públicas las propiedades de la función de caller y arguments . El hecho es que la caller que caller , por ejemplo, puede dar acceso a la función que llamó a la función cuya propiedad de la caller que caller estamos accediendo.

El objeto de arguments almacena los argumentos pasados ​​a la función cuando se llamó. Por ejemplo, si tenemos una función fn , esto significa que a través de fn.caller puede acceder a la función que llamó a la función, y usando fn.arguments puede ver los argumentos pasados ​​a fn cuando se llamó.

Estas características plantean un riesgo potencial de seguridad. Como resultado, el acceso a estas propiedades está prohibido en modo estricto.

 function secretFunction() {  'use strict';  secretFunction.caller;  secretFunction.arguments; } function restrictedRunner() {  return secretFunction(); } restrictedRunner(); 

En el ejemplo anterior, no podemos, en modo estricto, acceder a secretFunction.caller y secretFunction.arguments . El hecho es que estas propiedades se pueden usar para obtener una pila de llamadas a funciones. Si intenta ejecutar este código, se generará una excepción TypeError .

En modo estricto, los identificadores que pueden usarse en futuras versiones de JavaScript no pueden usarse para nombrar variables o propiedades de objetos. Por ejemplo, estamos hablando de los siguientes identificadores: implements , interface , let , package , private , protected , public , static y yield .

En ES2015 y en versiones posteriores del estándar, estos identificadores se convirtieron en palabras reservadas. Y no se pueden usar para nombrar variables o propiedades en modo estricto.

Resumen


El modo estricto es un estándar que existe desde hace muchos años. Disfruta de un soporte de navegador extremadamente amplio. Los problemas con el código de modo estricto solo pueden ocurrir en navegadores antiguos, como Internet Explorer.

Los navegadores modernos no deberían tener dificultades con el modo estricto de JavaScript. Como resultado, podemos decir que este modo debe usarse para evitar errores "silenciosos" y aumentar la seguridad de la aplicación. Los errores silenciosos se convierten en excepciones que impiden la ejecución de programas y, en términos de mejorar la seguridad, por ejemplo, se pueden observar mecanismos de modo estricto que restringen la eval y evitan el acceso a la pila de llamadas de función. Además, el uso del modo estricto facilita la optimización del código con los motores JS y obliga al programador a manejar cuidadosamente las palabras reservadas que pueden encontrar uso en futuras versiones de JavaScript.

Estimados lectores! ¿Utiliza el modo estricto cuando escribe código JS para sus proyectos?


Source: https://habr.com/ru/post/477284/


All Articles