MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Esta traducción está incompleta. Por favor, ayuda a traducir este artículo del inglés.

El modo estricto de ECMAScript 5 es una forma de optar explicitamente por una variante restringida de JavaScript. El modo estricto no es sólo un subconjunto: intencionalmente tiene diferente semántica que código normal. Los navegadores que no soportan el modo estricto ejecutarán el código con un modo diferente de los que sí lo soportan, así que no hay que usar en el modo estricto sin hacer pruebas previas. Código en modo estrico y en no estricto pueden coexistir, de modo que código puede migrarse a modo estricto incrementalmente.

El modo estricto hace varios cambios en la semántica normal de JavaScript. Primero, elimina algunos errores silenciosos de JavaScript haciendo que lancen excepciones. Segundo, corrige errores que hacen que sea difícil para los motores de JavaScript realizar optimizaciones: a veces, el código escrito en modo estricto puede correr más rápido que el que no es estricto. Tercero, el modo estricto prohibe cierta sintaxis que es probable que sea definida en futuras versiones de ECMAScript.

Vea transitioning to strict mode, si desea cambiar su código para trabajar en la variante estricta de JavaScript.

Invocando el modo estricto

El modo estricto se aplica a un script por completo o a funciones individuales. No se aplica a bloques entre corchetes {} ; intentar aplicarlo en tales contextos no hace nada. Código eval, código Function, atributos de manejadores de eventos, cadenas pasadas a setTimeout, y similares son scripts enteros, de modo que invocar modo estricto en tales contextos funciona como se espera.

Modo estricto para scripts

Para invocar el modo estricto en todo un script, escriba exactamente "use strict" (o 'use strict';) antes de cualquier otra sentencia.

// Whole-script strict mode syntax
"use strict";
var v = "Hola! Soy un modo estricto para script!";

Esta sintaxis tiene un problema que ya ha afectado a cierta página bien conocida: no es posible concatenar ciegamente scripts no confictivos entre sí. Si concatena un script en modo estricto con otro que no lo es, la concatenación de ambos producirá código en  modo estricto. Lo contrario también es cierto: código en modo no estricto mas código estricto produce código que no es estricto. Concatenar scripts no produce problemas si todos están en modo estricto (o si todos están en modo no estricto). El problema es mezclar scripts en modo estricto con scripts en modo no estricto. Por eso se recomienda habilitar el modo estricto a nivel de función solamente (al menos durante el periodo de transición de un programa).

Otra opción es envolver el contenido completo del script en una función y tener esa función externa en modo estricto. Así se elimina el problema de la concatenación, pero entonces usted tiene que hacerse cargo de exportar explícitamente las variables globales fuera del alcance de la función.

Modo estricto para funciones

De forma similar, para invocar el modo estricto para una función, escriba exactamente "use strict" (o 'use strict';) en el cuerpo de la función antes de cualquier otra sentencia.

function strict(){
  // Function-level strict mode syntax
  'use strict';
  function nested() { return "And so am I!"; }
  return "Hi!  I'm a strict mode function!  " + nested();
}
function notStrict() { return "I'm not strict."; }

Cambios en modo estricto

El modo estricto cambia la sintaxis y el comportamiento en tiempo de ejecución. Los cambios generalmente caen dentro de estas categorías: cambios que convierten erratas en errores (como errores de sintaxis o en tiempo de ejecución), cambios que simplifican como una variable particular es calculada, cambios que simplifian el uso de eval y arguments, cambios que hacen más fácil escribir JavaScript "seguro", y cambios que anticipan la evolución futura de EMACScript.

Convirtiendo erratas en errores

El modo estricto cambia algunos errores de sintaxis tolerados en modo no estricto y los convierte en errores.  JavaScript fue diseñado de modo que fuera fácil para programadores novatos, y puede haber operaciones semánticas que deberían ser errores pero son  tratadas como libres de error. A veces esto sirve para solucionar el problema en el momento, pero puede crear problemas más graves en el futuro. El modo estricto trata las erratas como errores, para que puedan ser descubiertas y subsanadas inmediatamente.

En primer lugar, el modo estricto hace imposible crear variables globales por accidente. En JavaScript no estricto, si se escribe mal una variable en una asignación, se creará una nueva propiedad en el objeto globlal y el código continuará "trabajando" como si nada (aunque es posible que el código asi escrito falle en el futuro, en concreto, en JavaScript más moderno). En modo estricto, cualquier asignación que produzca variables globales por accidente lanzará un error:

"use strict";
                       // Asumiendo que exista una variable global llamada mistypedVariable
mitipodeVariable = 17; // esta línea lanza un ReferenceError debido a
                       // una errata en el nombre de la variable

En segundo lugar, el modo estricto lanza una excepción en asignaciones que de otro modo fallarían silenciosamente. Por ejemplo, NaN es una variable que no puede ser asignada. En un código normal, asignar a NaN una variable no tiene efectos; el programador no recibe ningún mensaje de error. En cambio, en modo estricto, si se intenta asignar un valor a NaN, el programador recibirá una exepción. Cualquier asignación que falle silenciosamente en código normal (asignaciones a una propiedad de no escritura, asignaciones a una propiedad get, asignaciones a una nueva propiedad o a un objecto no extendible) lanzará una exepción en modo estricto:

"use strict";
// Asignación a un no-escritura global
var undefined = 5;
var Infinity = 5;

// Asignación a una propiedad de no-escritura
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // lanza un TypeError

// Asignación a una propiedad de tipo getter
var obj2 = { get x() { return 17; } };
obj2.x = 5; // lanza un TypeError

// Asignación a una nueva propiedad en un objeto no-extendible
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // lanza un TypeError

En tercer lugar, el modo estricto lanza una excepción al intentar eliminar propiedades no eliminables (mientra que en código normal el intento no tendría ningún efecto):

"use strict";
delete Object.prototype; // lanza TypeError

En cuarto lugar, la versión de modo estricto anterior a Gecko 34 requiere que todas las propiedades nombradas en un objeto sean únicas. En código normal se pueden duplicar nombres, siendo el último el que determina el valor de la propiedad. Pero como el último es el único que hace algo, la duplicidad da origen a errores si el código se modifica para cambiar el valor de la propiedad. Duplicar nombres de propiedades es un error de sintaxis en modo estricto.

"use strict";
var o = { p: 1, p: 2 }; // !!! syntax error

En quinto lugar, el modo estricto requiere que los nombres de los parámetros de una función sean únicos. En código normal, el último argumento repetido oculta argumentos anteriores con el mismo nombre. Estos argumentos permanecen disponibles a través de arguments[i], de modo que no son completamente inaccesibles. Aun así, esta ocultación tiene poco sentido y es probablemente indeseable (pues puede ocultar por ejempo un error al teclear una letra). Por lo tanto, en modo estricto, duplicar nombres de argumentos es un error de sintaxis.

function sum(a, a, c){ // !!! syntax error
  "use strict";
  return a + b + c; // wrong if this code ran
}

En sexto lugar, en modo estricto ECMAScript 5 se prohíbe la notación octal. La notación octal no es parte de ECMAScript 5, pero está soportada en todos los navegadores al poner como prefijo un cero al número: 0644 == 420 y "\045" === "%". En EMACScript 6 los números octales están soportados al añadir el prefijo "0o" a un número, por ejemplo:

var a = 0o10; // ES6: Octal

A veces los programadores novatos creen que al poner un cero como prefijo, esto no cambia el significado semántico, de modo que lo usan como una forma de alinear el texto, sin saber que esto cambia el valor del número. La sintaxis octal rara vez es útil y puede ser usada equivocadamente, de modo que en modo estricto, utilizar notación octal causa un error de sintaxis:

"use strict";
var sum = 015 + // !!! syntax error
          197 +
          142;

Simplificación en el uso de variables

El modo estricto simplifica el modo en que el nombre de una variable es asignada a un variable particular en el código. Muchas optimizaciones del compilador se basan en la habilidad para decir el lugar específico en que una variable está almacenada, lo cual es crítico para una optimización completa del código JavaScript. Algunas veces JavaScript hace que este mapeo básico del nombre de una variable y su valor no suceda hasta que no se está en tiempo de ejecución. El modo estricto elimina muchos de los casos en los que esto pasa, de modo que el compilador puede optimizar mejor el código que es estricto.

Primero, el modo estricto prohibe el uso de with. El problema con with es que cualquier nombre dento del bloque pude ser mapeado a una propiedad del objecto pasado como argumento, o a una variable en su alcance circundante: es imposible saber de antemano cuál será. El modo estricto hace que el uso de with sea un error de sintaxis, de modo que no hay oportunidad de una variable dentro de un with refererirse a una dirección desconocida en tiempo de ejecución:

"use strict";
var x = 17;
with (obj) // !!! syntax error
{
  // If this weren't strict mode, would this be var x, or
  // would it instead be obj.x?  It's impossible in general
  // to say without running the code, so the name can't be
  // optimized.
  x;
}

En vez de usar with, existe la simple alternativa de asignar el objecto a una variable de nombre menor, y después acceder a la propiedad correspondiente de esa variable.

Segundo, el uso de eval en modo estricto no introduce nuevas variables en en alcance circundante. En código normal, eval ("var x;") introduce una variable x dentro del la función circundante o el alcance global. Esto significa que, en general, en una función que contiene una llamada eval a cada nombre que no se refiera a un argumento o a una variable local, debe ser mapeada a una definición en particular en tiempo de ejecución (debido a que eval puedo haber introducido una nueva variable que podría ocultar una variable más externa). En modo estricto eval crea variables solo para el código siendo evaluado, de modo que eval no puede afectar si el nombre se refiere a una variable local o externa.

var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
assert(x === 17);
assert(evalX === 42);

En el ejemplo anterior, si la función eval es invocada por una expresion de la forma eval (...) en código de modo estricto, el código será evaluado en modo estricto. El código puede explícitamente invocar el modo estricto, pero no es necesario.

function strict1(str){
  "use strict";
  return eval(str); // str will be treated as strict mode code
}
function strict2(f, str){
  "use strict";
  return f(str); // not eval(...): str is strict if and only
                 // if it invokes strict mode
}
function nonstrict(str){
  return eval(str); // str is strict if and only 
                    // if it invokes strict mode
}

strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");

Así los nombres en modo estricto usando eval se comportan identicamente a los nombres en modo estricto no siendo evaluados como resultado de eval.

Tercero, el modo estricto prohíbe eliminar nombres planos. De este modo, delete name produce un error de sintaxis.

"use strict";

var x;
delete x; // !!! syntax error

eval("var y; delete y;"); // !!! syntax error

Haciendo eval y arguments más simples

El modo estricto hace que el uso de arguments y eval sea más intuitivo. Ambos envuelven un considerable mistisismo en código normal: eval al añadir o remover los enlaces y cambiar los valores de dichos enlaces, y arguments al poder sustituir los nombres de los argumentos por propiedades indexadas. El modo estricto ofrece un gran paso al tratar eval y arguments como palabras clave, aunque soluciones finales no estarán disponibles hasta futuras ediciones de ECMAScript.

Primero, las palabras eval y arguments no pueden ser ligadas o asignadas en la sintaxis del lenguaje. Cualquier intento producirá un error de sintaxis:

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

Segundo, el modo estricto no permite usar alias en elementos del objecto argument creados dentro de la función. En un función en código normal cuyo primer parámetro sea args, si se cambia el valor de args también se cambiará del de arguments[0], y vice versa (a menos que ningún parámetro sea proporcionado o arguments[0] sea eliminado). El objecto arguments para el modo estricto almacena los parámetros originales cuando la función es invocada. arguments[i] no guarda el valor del correpondiente nombre del parámetro, ni tampoco un parámetro con nombre guarda el valor correspondiente de arguments[i].

function f(a){
  "use strict";
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
assert(pair[0] === 42);
assert(pair[1] === 17);

Tercero, aguments.callee no es soportado. En código normal arguments.callee se refiere simplemente a la función externa que llamó la función actual, lo cual no parece tener mucha utilidad. Además arguments.callee merma el desempeño de funciones en linea pues debe ser posible proveer la referencia de la función que llamó la función original cada vez que arguments.calle es usado. arguments.callee en modo estrico es una propiedad no eliminable y lanza una exepción cuando se le asigna un valor o se intenta regresar su valor.

"use strict";
var f = function() { return arguments.callee; };
f(); // throws a TypeError

Haciendo JavaScript más seguro

El modo estricto hace más fácil el escribir código "seguro" en JavaScript. Algunos sitios web ofrecen ahora medios para que los usuarios codifiquen en JavaScript para que el código corra en el sitio en beneficio de otros usuarios. JavaScript tienen la capacidad de acceder a la información privada de los usuarios en el navegador, de modo que JavaScript debe ser parcialmente transformado antes de correr, para limitar el acceso a alguna funcionalidad prohibida. La fexibilidad de JavaScript hace casi imposible hacer esto sin hacer revisiones en tiempo de ejecución. Algunas funciones del lenguaje son tan influyentes que causan grandes problemas de rendimiento al hacer revisiones de seguridad en tiempo de ejecución.

Primero, el valor this pasado a una función en modo estricto no debe ser forzosamente un objeto. Para una función normal, this siempre es un objeto: ya sea el objeto por default al pasar this, el valor empaquetado si se llamón un Boolean, string o entero, o el objeto global si se llama con un undefined o null. (Usar call,apply, o bind para especificar un valor de this particular). Este empaquetamineto automático al pasar valores a una función tiene un costo en el rendimiento, no solo eso, si no que al exponer el objeto globarl en los navegadores es un riesgo de seguridad, debido d que el objeto global proveé aceso a una funcionalidad que el código de JavaScritp "seguro" debe de restringir. Así, en una función en modo estricto , el valor de this no está empaquetado dentro de un objecto, y si no es especificado, this toma el valor de undefined.

"use strict";
function fun() { return this; }
assert(fun() === undefined);
assert(fun.call(2) === 2);
assert(fun.apply(null) === null);
assert(fun.call(undefined) === undefined);
assert(fun.bind(true)() === true);

Esto significa, entre otras coasas, que en los navegadores no es posible hacer referencia al objeto window a traves de this dentro de una función en modo estricto.

Segundo, en modo estriccto no es más posible "recorrer" el stack de JavaScript a través de extensiones de ECMAScript. En código normal con estas extensiones, cuando una función llamada fun está en medio de su ejecución, fun.caller es la función que más recientemente llamó a fun, y fun.arguments son los paremetros para esa invocación de fun. Ambas extensiones son problematicas para JS "seguro", debido a que permite acceder a funciones "privilegiadas" y sus argumentos. Si fun está en modo estricto, ambos fun.caller y fun.arguments lanzan una excepción cuando son llamadas.

function restricted()
{
  "use strict";
  restricted.caller;    // throws a TypeError
  restricted.arguments; // throws a TypeError
}
function privilegedInvoker()
{
  return restricted();
}
privilegedInvoker();

Tercero, en funciones de modo estricto, el objeto arguments no proveé acceso a las variables usadas al llamar a la función. En algunas implementaciones viejas de de ECMAScript, arguments.caller era un objeto cuyas propiedades apuntaban a las variables en la función. Esto es una amenaza de seguridad por que rompe la habilidad de ocultar valores privilegiados a través de la abstracción de la función; además frena algunas optimizaciones. Por estas razones los navegadores modernos no la implementan. Por su funcionalidad a lo largo de los años, arguments.caller en una función de modo estricto es una propiedad de lanza una excepción cuando es usada.

"use strict";
function fun(a, b)
{
  "use strict";
  var v = 12;
  return arguments.caller; // throws a TypeError
}
fun(1, 2); // doesn't expose v (or a or b)

Preparando el camino para futuras versiones de ECMAScript

Las futuras versiones de ECMAScript introducirán nuevos cambios, y el modo estricto en ECMAScript 5 aplica algunos de esos cambios para hacer una transición más suave. Será más fácil hacer cambios si las bases de esos cambios son prohibidas en modo estricto.

Primero, en modo estricto una lista de identificadores se convierten en palabras reservadas. Estas palabras son implementsinterfaceletpackageprivateprotectedpublicstatic, y yield. De modo que en modo estricto, no se pueden usar estas palabras para nombrar variables o como argumentos.

function package(protected){ // !!!
  "use strict";
  var implements; // !!!

  interface: // !!!
  while (true){
    break interface; // !!!
  }

  function private() { } // !!!
}
function fun(static) { 'use strict'; } // !!!

Two Mozilla-specific caveats: First, if your code is JavaScript 1.7 or greater (for example in chrome code or when using the right <script type="">) and is strict mode code, let and yield have the functionality they've had since those keywords were first introduced. But strict mode code on the web, loaded with <script src=""> or <script>...</script>, won't be able to use let/yield as identifiers. Second, while ES5 unconditionally reserves the words class, enum, export, extends, import, and super, before Firefox 5 Mozilla reserved them only in strict mode.

Segundo, strict mode prohibits function statements not at the top level of a script or function. In normal code in browsers, function statements are permitted "everywhere". This is not part of ES5 (or even ES3)! It's an extension with incompatible semantics in different browsers. Future ECMAScript editions will hopefully specify new semantics for function statements not at the top level of a script or function. Prohibiting such function statements in strict mode "clears the deck" for specification in a future ECMAScript release:

"use strict";
if (true){
  function f() { } // !!! syntax error
  f();
}

for (var i = 0; i < 5; i++){
  function f2() { } // !!! syntax error
  f2();
}

function baz(){ // kosher
  function eit() { } // also kosher
}

This prohibition isn't strict mode proper, because such function statements are an extension of basic ES5. But it is the recommendation of the ECMAScript committee, and browsers will implement it.

Strict mode in browsers

The major Browsers now implement strict mode. However, don't blindly depend on it since there is still a considerable amount of Browser versions used in the wild which has only partial support for strict mode or does not support it at all (e.g. Internet Explorer below version 10!). Strict mode changes semantics. Relying on those changes will cause mistakes and errors in browsers which don't implement strict mode. Exercise caution in using strict mode, and back up reliance on strict mode with feature tests that check whether relevant parts of strict mode are implemented. Finally, make sure to test your code in browsers that do and don't support strict mode. If you test only in browsers that don't support strict mode, you're very likely to have problems in browsers that do, and vice versa.

Specifications

Specification Status Comment
ECMAScript 5.1 (ECMA-262)
The definition of 'Strict Mode Code' in that specification.

ECMAScript 5.1 (ECMA-262)
The definition of 'Strict mode restriction and exceptions' in that specification.
Standard Initial definition.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Strict Mode Code' in that specification.

ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Strict mode restriction and exceptions' in that specification.
Standard  

See also

Etiquetas y colaboradores del documento

 Última actualización por: nhuamani,