JavaScript’s Strict Mode and Why You Should Use It

Starting with ECMAScript 5, developers are able to place their code into a more constrained form of execution known as strict mode.  Strict mode improves JavaScript code by enforcing better programming practices and eliminating some of the language’s insecure and ill-advised features.  Strict mode is enabled by adding the following directive to your code:

"use strict";

The “use strict”; directive can be used in two ways.  The first method of invoking strict mode is at the file level.  By adding the directive at the beginning of a file (the directive may only be preceded by comments and whitespace), strict mode is enabled in a global context.  This means that all of your code will be evaluated in strict mode.  Caution must be taken when concatenating strict and non-strict scripts together.  Placing a strict script first will force the non-strict script to be evaluated in strict mode.  Placing a non-strict script first will cause the opposite behavior.  This caused some problems for Amazon.

The second way to enable strict mode is at the function level.  To enable this level of strict mode, place the “use strict”; directive at the beginning of the function body.  As with global strict mode, the directive may only be preceded by whitespace and comments.  Using strict mode at the function level allows a programmer to mix and match strict and non-strict functions in the same file.  This is useful when some legacy code relies on features that have been deprecated in strict mode.  The following example shows how strict and non-strict functions can coexist in a single file.

function foo() {
  "use strict";
  // this function is executed in strict mode
}

function bar() {
  // this function is executed in non-strict mode
}

One of the nice things about strict mode is its backward compatibility.  Older versions of JavaScript will treat the “use strict”; directive as a meaningless string literal and ignore it.  However, newer versions of JavaScript will give the statement special treatment and switch to strict mode.  For browsers that support strict mode, the following restrictions apply.

Implicit Global Variable Declaration

JavaScript has an interesting way of handling variable declarations.  Variables that are not declared using the var keyword are implied to be global variables.  The following piece of code uses three variables – ‘x’, ‘y’, and ‘z’.

function foo() {
  var x;
  var z;

  x = 1;
  y = 2;
  z = x + y;
}

Notice that only the variables ‘x’ and ‘z’ are declared using the var keyword.  There is a good chance that the programmer also meant to declare ‘y’, but mistakenly did not.  The code will execute properly, but with the side effect of creating a global variable named ‘y’ with the value 2.  Since window is the global object, this is equivalent to writing:

window.y = 2;

This behavior can be problematic if ‘y’ is already defined elsewhere and is expected to have a different value.  This leads to code that doesn’t scale well and is difficult to debug.  Enabling strict mode will catch this problem.  Instead of making ‘y’ a global variable, an exception will occur.  The exception shown in Chrome looks like this:

ReferenceError: y is not defined

The with Statement

The with statement provides a shorthand notation for working with an object’s properties.  Inside a with statement, it can be difficult to tell if a variable belongs to the object in question or some other scope.  The following code uses a with statement to output the document’s title.  There is also a local variable named ‘title’, which is ignored inside the with statement.  In a more complex piece of code, a programmer could easily introduce bugs related to variable scoping when using with statements.

function foo() {
  var title = "Not the page title";
  with (document) {
    write(title + "<br />");
    write("contains a with statement");
  }
}

In strict mode, the with statement has been completely disabled.  Any attempt to use the with statement will result in the following syntax error.  Note:  A much better idea is to assign the object to a variable and access it’s properties via the variable.

SyntaxError: Strict mode code may not include a with statement

Identifier Naming

Strict mode places several naming restrictions on variables, functions, and parameters.  The strings ‘eval’ and ‘arguments’ cannot be used as identifiers, nor can they have values assigned to them.  Because JavaScript has a built-in ‘eval’ function and ‘arguments’ object, this eliminates possible confusion.  Attempting to use ‘eval’ or ‘arguments’ as a name results in the following exception:

SyntaxError: Variable name may not be eval or arguments in strict mode

Additionally, identifiers can no longer use any of the following future reserved keywords:

  • implements
  • interface
  • let
  • package
  • private
  • protected
  • public
  • static
  • yield

this Usage

Use of a ‘this’ variable is common in object-oriented programming.  Inside a function, the ‘this’ variable points to the object that owns the function.  However, when a function does not belong to any specific object, the ‘this’ variable points to the global object (window).  Strict mode removes accidental or malicious access of the global object by assigning ‘this’ a value of undefined.  If a function is owned by an object, then ‘this’ still points to that object as expected.  In the following example, the function ‘foo’ returns undefined.

function foo() {
  "use strict";
  return this;
}

Read-only Properties

JavaScript allows developers to create read-only properties on objects.  Attempts to write a new value to a read-only property fail silently in non-strict code.  In other words, the property’s value remains unchanged, but the program does not provide any warning/error.  In strict mode, such behavior will cause the script to throw an exception.  The following example creates a read-only property named ‘prop1′.  In strict mode, the subsequent assignment of ‘prop1′ causes a TypeError exception.

function foo() {
  "use strict";
  var obj = Object.defineProperties({}, {
              prop1 : {
                value : 1,
                writable : false
              }
            });

  obj.prop1 = 2;
}

Non-extensible Objects and Variables

In JavaScript, adding new properties to an object is trivial – just assign a value to it.  JavaScript also provides a mechanism for preventing the addition of new properties.  By setting an object’s internal ‘extensible’ attribute to false, the addition of new properties to an object will fail silently.  Once again, strict mode changes silent failure to a TypeError exception.  The following code attempts to add a new property to a non-extensible object.

function foo() {
  "use strict";
  var obj = {prop1 : 1};

  Object.preventExtensions(obj);
  obj.prop2 = 2;
}

The object ‘obj’ is constructed with a single property, ‘prop1.’  When ‘Object.preventExtensions’ is called, ‘obj’ becomes non-extensible.  The attempt to add ‘prop2′ to the object results in the following exception:

TypeError: Can't add property prop2, object is not extensible

Duplicate Parameters and Properties

Non-strict JavaScript allows objects to contain multiple properties with the same name.  When the same name is used multiple times, only the last declaration is used.  Strict mode requires that all property names are unique.  In the following example, the object ‘obj’ contains two properties named ‘prop1′.  In non-strict mode, the value of ‘prop1′ would be 3.  However, when strict mode is enabled a syntax error occurs.

// while in strict mode
obj = {
  prop1 : 1,
  prop2 : 2,
  prop1 : 3
};

Similarly, non-strict functions may have multiple parameters with the same name.  In strict mode, this is not allowed.  In the following example, duplicating ‘param1′ causes a syntax error.

function foo(param1, param1) {
  "use strict";
  alert(param1);
}

 eval Variables

Non-strict code can use the ‘eval’ function to add new variables to the surrounding scope.  Prior to native JSON support in browsers, ‘eval’ was commonly (and unsafely) used to construct objects from strings.  The constructed objects then became a part of the surrounding scope.  In strict mode, ‘eval’ cannot introduce new variables.  When executed in strict mode, the following piece of code will not introduce the ‘bar’ variable into the surrounding scope.  Note:  if a function containing ‘eval’ is executed in strict mode, then the code inside the ‘eval’ function is also executed in strict mode.

// while in strict mode
eval("var bar = 10;");

The delete Operator

The delete operator is used to remove properties from objects.  However, some properties cannot be deleted.  Non-configurable properties are of the variety that cannot be deleted.  Non-strict code will fail silently when an attempt is made to delete a non-configurable property.  Such an attempt throws a TypeError exception when executing in strict mode.  In the following example, the object ‘obj’ has a non-configurable property named ‘prop1′ and a configurable property named ‘prop2′.  Since ‘prop2′ is configurable, it is perfectly acceptable to delete it.  An exception is not thrown until the attempt to delete ‘prop1′ is made.

function foo() {
  "use strict";
  var obj = Object.defineProperties({}, {
              prop1 : {
                value : 1,
                configurable : false
              },
              prop2 : {
                value : 2,
                configurable : true
              }
            });

  delete obj.prop2;
  delete obj.prop1;
}

The delete operator is intended to work on object properties.  Attempting to delete normal variables and functions will result in a syntax error.  All of the delete operations in the following example will fail.

function foo(param1) {
  "use strict";
  var bar = 1;
  function baz() {};

  delete param1;
  delete bar;
  delete baz;
}

Using arguments, caller, and callee

When a function is called, a special object named ‘arguments’ is created in the function’s scope.  The ‘arguments’ object contains an array that is mapped to the parameters passed to the function.  In the following example ‘arguments[0]‘ and ‘arg1′ hold the same value, as do ‘arguments[1]‘ and ‘arg2′.  In non-strict mode, updating one value automatically updates the value it maps to.  At the end of ‘bar’, the values of ‘arg1′ and ‘arg2′ have been swapped even though values were only assigned to the ‘arguments’ array.  In strict mode, the aliased values are not automatically updated.  Therefore, when run in strict mode, the values of ‘arg1′ and ‘arg2′ are unchanged at the end of ‘bar’.

function foo() {
  bar(1, 2);
}

function bar(arg1, arg2) {
  var temp = arguments[0];
  arguments[0] = arg2;
  arguments[1] = temp;
  alert(arg1 + " " + arg2);
}

The ‘arguments’ object also contains a pointer to the function that is currently executing.  The current function is referred to as the callee, and can be referenced using ‘arguments.callee’.  This syntax is only useful inside an anonymous function, because anonymous functions do not have names.  In any other case, it makes more sense to refer to the callee by name.  In strict mode, access to ‘arguments.callee’ is not allowed.

A similar method can be used to determine where a function call was made from.  An ‘arguments.caller’ object was available in older browsers, but has since been deprecated. However, the calling method can still be determined using ‘arguments.callee.caller’.  Strict mode also prohibits access to the caller.  In the following example, ‘bar’ is not in strict mode.  However, attempting to access ‘arguments.callee.caller’ will still fail because ‘foo’ is a strict mode function.

function foo() {
  "use strict";
  bar(1, 2);
}

function bar(arg1, arg2) {
  var caller = arguments.callee.caller
}

Octals

Octal variables represent numbers in the base-8 number system.  They are rarely used and have a very confusing syntax.  Positive octal numbers are prefixed with a ’0′ while negative octals begin with ‘-0′.  For example, declaring the octal number 100 looks like this:

var foo = 0100;

Since people tend to ignore leading zeros, this can easily be confused with the decimal value 100.  However, a quick call to ‘parseInt()’ shows that the octal value is actually equal to 64 when converted to decimal.  To resolve this problem, strict mode disallows the use of octals.  Octal variables and octal escape sequences are both treated as syntax errors in strict mode.


6 thoughts on “JavaScript’s Strict Mode and Why You Should Use It

  1. Hi Cjihrig,

    Thank you very much for writing this excellent article, nicely explains all the uses and caveats of “use strict”
    Simply Great!

  2. I’ve been trying to figure out “use strict” off and on for months and Google just wasn’t providing the complete, clear and concise answer I was looking for :-/ Great job!

    PS. howdy from a fellow Ihrig!

  3. learning javascript, put my code through jshint and was given a missing “use strict” error. Added “use stri t” and now get

    Missing ‘new’ prefix when invoking a constructor.

    everywhere, why? lol

    • This message is probably not related to the fact that you are using strict mode. I’m assuming that you are creating objects like this:

      var foo = Date();

      and jshint would like you to create them like this:

      var foo = new Date();