Transitioning to strict mode

  • Revision slug: JavaScript/Reference/Functions_and_function_scope/Strict_mode/Transitioning_to_strict_mode
  • Revision title: Transitioning to strict mode
  • Revision id: 356349
  • Created:
  • Creator: rwaldron
  • Is current revision? No
  • Comment

Revision Content

ECMAScript 5 introduced strict mode which is now implemented in all major browsers (including IE10). However, as a JavaScript developer, the transition path may not always be clear. This goal of this document is to explain how strict mode effects existing JavaScript code and provide transition guidance for developers.

Gradual transition

Strict mode has been thought so that the transition to it can be made gradually. It is possible to change each file individually and even to transition code to strict mode at function granularity.

Differences from non-strict to strict

Syntax errors

When adding "use strict";, the following cases will throw a SyntaxError before the script is executing:

  • Octal syntax var n = 023;
  • with statement
  • Using delete on a variable name delete myVariable;
  • Using eval or arguments as variable or function argument name
  • Using one of the newly reserved keyword (in prevision for ECMAScript 6): implements, interface, let, package, private, protected, public, static, and yield
  • Declaring function in blocks if(a<b){ function f(){} }
  • Obvious errors
    • Declaring twice the same name for a property name in an object literal {a: 1, b: 3, a: 7}
    • Declaring two function arguments with the same name function f(a, b, b){}

These errors are good, because they reveal plain errors or bad practices. They occur before the code is running.

Runtime errors

JavaScript used to silently fails in contexts where what was done was an error. Strict mode throws in such cases. If your code base contains such cases, testing will be necessary to be sure nothing is broken. A test suite with 100% coverage should catch all these errors.

Setting a value to an undeclared variable

function f(x){
  "use strict";
  var a = 12;
  b = a + x*35; // error!
}
f();

This used to change a value on the global object which is rarely the expected effect. If you really want to set a value to the global object, pass it as argument and explicitely assign as a property:

var global = this; // in the top-level context, "this" always refers the global object
function f(){
  "use strict";
  var a = 12;
  global.b = a + x*35;
}
f();

Trying to delete a non-configurable property

"use strict";
delete Object.prototype; // error!

In non-strict, this would silently fail, in contradiction with the user expectation.

Poisonned arguments and function properties

Accessing arguments.callee, arguments.caller, anyFunction.caller or anyFunction.arguments throws an error in strict mode. The only legitimate use case would be to reuse a function as in:

// example taken from vanillajs: http://vanilla-js.com/
var s = document.getElementById('thing').style;
s.opacity = 1;
(function(){ 
  if((s.opacity-=.1) < 0)
    s.display="none";
  else
    setTimeout(arguments.callee, 40);
})();

which can be rewritten as:

"use strict";
var s = document.getElementById('thing').style;
s.opacity = 1;
(function fadeOut(){ // name the function
  if((s.opacity-=.1) < 0)
    s.display="none";
  else
    setTimeout(fadeOut, 40); // use the name of the function
})();

Semantic differences

These differences are very subtle differences. It's possible that a test suite doesn't catch this kind of subtle differences. Careful review of your code base will probably be necessary to be sure these differences don't affect the semantics of your code. Fortunately, this careful review can be done gradually down the the function granularity.

this in function calls

In function calls like f(), the this value was the global object. In strict mode, it is now undefined. When a function was called with call or apply, if the value was a primitive value, this one was boxed into an object (or the global object for undefined and null). In strict mode, the value is passed directly without conversion or replacement.

arguments doesn't alias named function arguments

In non-strict mode, modifying a value in the arguments object modifies the corresponding named argument. This made optimizations complicated for JavaScript engine and made code harder to read/understand. In strict mode, the arguments object is created and initialized with the same values than the named arguments, but changes to either the arguments object or the named arguments aren't reflected in one another.

Change to eval

In strict mode code, eval doesn't create new variable in the scope from which it was called. Also, of course, in strict mode, the string is evaluated with strict mode rules. Thorough testing will need to be performed to make sure nothing breaks. Not using eval if you don't really need it may be another very pragmatic solution.

Revision Source

<p>ECMAScript 5 introduced <a href="/en-US/docs/JavaScript/Strict_mode" title="/en-US/docs/JavaScript/Strict_mode">strict mode</a> which is now implemented in all major browsers (including IE10). However, as a JavaScript developer, the transition path may not always be clear. This goal of this document is to explain how strict mode effects existing JavaScript code and provide transition guidance for developers.</p>
<h2 id="Gradual_transition">Gradual transition</h2>
<p>Strict mode has been thought so that the transition to it can be made gradually. It is possible to change each file individually and even to transition code to strict mode at function granularity.</p>
<h2 id="Differences_from_non-strict_to_strict">Differences from non-strict to strict</h2>
<h3 id="Syntax_errors">Syntax errors</h3>
<p>When adding <code>"use strict";</code>, the following cases will throw a <a href="/en-US/docs/Core_JavaScript_1.5_Guide/SyntaxError" title="/en-US/docs/Core_JavaScript_1.5_Guide/SyntaxError">SyntaxError</a> before the script is executing:</p>
<ul>
  <li>Octal syntax <code>var n = 023;</code></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Statements/with" title="/en-US/docs/JavaScript/Reference/Statements/with"><code>with</code></a> statement</li>
  <li>Using <a href="/en-US/docs/JavaScript/Reference/Operators/delete" title="/en-US/docs/JavaScript/Reference/Operators/delete">delete</a> on a variable name <code>delete myVariable</code>;</li>
  <li>Using <code>eval</code> or <code>arguments</code> as variable or function argument name</li>
  <li>Using one of the newly reserved keyword (in prevision for ECMAScript 6): <code>implements</code>, <code>interface</code>, <code>let</code>, <code>package</code>, <code>private</code>, <code>protected</code>, <code>public</code>, <code>static</code>, and <code>yield</code></li>
  <li>Declaring function in blocks <code>if(a&lt;b){ function f(){} }</code></li>
  <li>Obvious errors
    <ul>
      <li>Declaring twice the same name for a property name in an object literal <code>{a: 1, b: 3, a: 7}</code></li>
      <li>Declaring two function arguments with the same name <code>function f(a, b, b){}</code></li>
    </ul>
  </li>
</ul>
<p>These errors are good, because they reveal plain errors or bad practices. They occur before the code is running.</p>
<h3 id="Runtime_errors">Runtime errors</h3>
<p>JavaScript used to silently fails in contexts where what was done was an error. Strict mode throws in such cases. If your code base contains such cases, testing will be necessary to be sure nothing is broken. A test suite with 100% <a href="http://en.wikipedia.org/wiki/Code_coverage" title="http://en.wikipedia.org/wiki/Code_coverage">coverage</a> should catch all these errors.</p>
<h4 id="Setting_a_value_to_an_undeclared_variable">Setting a value to an undeclared variable</h4>
<pre class="brush: js">
function f(x){
  "use strict";
  var a = 12;
  b = a + x*35; // error!
}
f();
</pre>
<p>This used to change a value on the global object which is rarely the expected effect. If you really want to set a value to the global object, pass it as argument and explicitely assign as a property:</p>
<pre class="brush: js">
var global = this; // in the top-level context, "this" always refers the global object
function f(){
  "use strict";
  var a = 12;
  global.b = a + x*35;
}
f();
</pre>
<h4 id="Trying_to_delete_a_non-configurable_property">Trying to delete a non-configurable property</h4>
<pre class="brush: js">
"use strict";
delete Object.prototype; // error!
</pre>
<p>In non-strict, this would silently fail, in contradiction with the user expectation.</p>
<h4 id="Poisonned_arguments_and_function_properties">Poisonned arguments and function properties</h4>
<p>Accessing <code>arguments.callee</code>, <code>arguments.caller</code>, <code>anyFunction.caller</code> or <code>anyFunction.arguments</code> throws an error in strict mode. The only legitimate use case would be to reuse a function as in:</p>
<pre class="brush: js">
// example taken from vanillajs: http://vanilla-js.com/
var s = document.getElementById('thing').style;
s.opacity = 1;
(function(){ 
  if((s.opacity-=.1) &lt; 0)
    s.display="none";
  else
    setTimeout(arguments.callee, 40);
})();</pre>
<p>which can be rewritten as:</p>
<pre class="brush: js">
"use strict";
var s = document.getElementById('thing').style;
s.opacity = 1;
(function fadeOut(){ // name the function
  if((s.opacity-=.1) &lt; 0)
    s.display="none";
  else
    setTimeout(fadeOut, 40); // use the name of the function
})();</pre>
<h3 id="Semantic_differences">Semantic differences</h3>
<p>These differences are very subtle differences. It's possible that a test suite doesn't catch this kind of subtle differences. Careful review of your code base will probably be necessary to be sure these differences don't affect the semantics of your code. Fortunately, this careful review can be done gradually down the the function granularity.</p>
<h4 id="this_in_function_calls"><code>this</code> in function calls</h4>
<p>In function calls like <code>f()</code>, the <code>this</code> value was the global object. In strict mode, it is now <code>undefined</code>. When a function was called with <a href="/en-US/docs/Core_JavaScript_1.5_Reference/Global_Objects/Function/call" title="/en-US/docs/Core_JavaScript_1.5_Reference/Global_Objects/Function/call">call</a> or <a href="/en-US/docs/Core_JavaScript_1.5_Reference/Global_Objects/Function/apply" title="/en-US/docs/Core_JavaScript_1.5_Reference/Global_Objects/Function/apply">apply</a>, if the value was a primitive value, this one was boxed into an object (or the global object for <code>undefined</code> and <code>null</code>). In strict mode, the value is passed directly without conversion or replacement.</p>
<h4 id="arguments_doesn't_alias_named_function_arguments"><code>arguments</code> doesn't alias named function arguments</h4>
<p>In non-strict mode, modifying a value in the <code>arguments</code> object modifies the corresponding named argument. This made optimizations complicated for JavaScript engine and made code harder to read/understand. In strict mode, the <code>arguments</code> object is created and initialized with the same values than the named arguments, but changes to either the <code>arguments</code> object or the named arguments aren't reflected in one another.</p>
<h4 id="Change_to_eval">Change to <code>eval</code></h4>
<p>In strict mode code, <code>eval</code> doesn't create new variable in the scope from which it was called. Also, of course, in strict mode, the string is evaluated with strict mode rules. Thorough testing will need to be performed to make sure nothing breaks. Not using eval if you don't really need it may be another very pragmatic solution.</p>
Revert to this revision