CuteMachine

JavaScript's Strict Mode

What is JavaScript's Strict Mode?

Strict mode is a directive (not a new keyword) that has been introduced in ES5. The directive tells the execution environment to run the code in strict mode.

Strict mode fixes many of JavaScript's language quirks. One of those language features is the with statement, which is not available in strict mode. Your program can benefit from improved error checking and security when the strict execution mode is enabled.

Some of the new additions to the JavaScript language implicitly turn on strict mode. For example, any code in ES6 modules or class bodies will run in strict mode.

Usually you can run all examples in my JS articles with the excellent RunJS REPL.1 But RunJS turns on strict mode automatically, which makes it hard to show the differences between strict mode and the so-called sloppy mode. I recommend you run the examples in the Multi-line Editor of the Firefox web developer tools.

How to Enable Strict Mode

It is straightforward to enable strict mode in your code. Just place the string "use strict" at the top of your program, and the strict mode rules will be applied. Notice that no new keywords have been introduced. You can add this string to any JS code. It will not cause any troubles in environments that do not support strict mode.

If you want to turn on the strict mode in a function only, you can add the directive at the top of the function body.

// Code here runs in non-strict mode
function runsInStrictMode() {
    "use strict"
    // Code here runs in strict mode
}
// Code here runs in non-strict mode

How to Check If The JS Script Runs In Strict Mode

There is no official way of checking if your code runs in strict mode, but you can write a function to test this. The following function returns true when called from a strict mode operating context.

function isStrictMode(){
    return !this;
} 

isStrictMode()    // true

For example, when calling isStrictMode() from a strict operating context will return true.

{
  function foo() {
    "use strict"
    function isStrictMode(){
        return !this;
    } 
    console.log(isStrictMode())
  }
  foo()    // true
}

When you run the code without the strict mode directive, isStrictMode() will return false.

{
  function foo() {
    function isStrictMode(){
        return !this;
    } 
    console.log(isStrictMode())
  }
  foo()    // false
}

Please do not run these code examples in RunJS but a browser console. Otherwise, you will get misleading results.

Improved Error Checking

In some areas, JavaScript does not provide good errors. In strict mode, error reporting has been improved for many such situations.

Ambiguous Function Parameters

If parameters have the same name in a function declaration, JavaScript will provide an error message to call our attention.

(function() {
  "use strict"
  function foo(bar, bar) {
    // do something
  }
})()
// SyntaxError: duplicate formal argument bar

In sloppy mode, you can declare functions having parameters with the same name, and JavaScript wouldn't bring it to our attention. Here is what happens when you use parameters with the same name.

(function() {
  function foo(bar, bar) {
    console.log(bar)
  }
  foo(2, 3)
})()
// 3

Assignments To Undeclared Variables

In sloppy mode, you can assign a value to an undeclared variable. When JavaScript does not find the variable, it will create a property with that value on the global object (window).

(function() {
  bar = 'pollution'
  console.log(window.bar)    // pollution
})()

With strict mode, JavaScript will raise a ReferenceError.

(function() {
  "use strict"
  bar = 'pollution'    // ReferenceError: assignment to undeclared variable bar
  console.log(window.bar)
})()

Function Calls

In sloppy mode, when you call a function (not a method), the function's this is automatically bound to the global object.

(function() {
  window.foo = 'bar'
  function foo() {
    console.log(this.foo)    // bar
  }
  foo()
})()

In the above example, this is bound to the global object (window, when you run this code in a browser). Therefore we see bar printed to the console when we run the code.

With strict mode, the same code will throw a TypeError because this is undefined.

(function() {
  "use strict"
  window.foo = 'bar'
  function foo() {
    console.log(this.foo)    // TypeError: this is undefined
  }
  foo()
})()

Read-only Object Properties

In JavaScript, we can create read-only properties on objects. We can define such properties with Object.defineProperty(). This method takes the object to which we want to add a property, the name of the new property, and a configuration object with the initial value for the new property and a flag indicating that it should be non-writable.

(function() {
  const obj = {}
  Object.defineProperty(obj, "pi", { value: 3.1415, writable: false })
  obj.pi = 42
  console.log(obj.pi)    // still 3.1415
})()

As you can see, we created a non-writable attribute pi. And indeed, when we tried to assign a new value to pi, the assignment failed.

The problem is that the operation fails silently.

In strict mode, when you assign a new value to a non-writeable property, you will get a TypeError.

(function() {
  "use strict"
  const obj = {}
  Object.defineProperty(obj, "pi", { value: 3.1415, writable: false })
  obj.pi = 42    // Uncaught TypeError: "pi" is read-only
})()

Non-extensible Objects

In non-strict mode, trying to add a new property to a non-extensible object fails silently.

(function() {
  const obj = { foo: 42 }
  Object.preventExtensions(obj)
  obj.bar = '18'
  console.log(obj)    // { foo: 42 }
})()

In strict mode, we will get a TypeError.

(function() {
  "use strict"
    
  const obj = { foo: 42 }
  Object.preventExtensions(obj)
  obj.bar = '18'    // Uncaught TypeError: can't define property "bar": Object is not extensible
})()

Errors For Non-qualified Deletions

If you try to delete a non-qualified identifier in the sloppy mode, you don't get an error. Instead, the delete operator fails silently, not so in strict mode.

(function() {
  "use strict"
  const foo = 42
  delete foo    // Uncaught SyntaxError: applying the 'delete' operator to an unqualified name is deprecated
})()

Restrictions In JavaScript's Strict Mode Operating Context

Besides the improved error reporting for some coding mistakes, the strict mode also restricts some language features.

Treating eval As A Keyword

In sloppy mode it was possible to overwrite eval which is pretty insecure as it is possible to do something like the following:

(function() {
  const eval = () => console.log('hello')
  eval()
})()

Overwriting eval is no longer possible in the strict mode as JavaScript now treats eval as a keyword.

(function() {
  "use strict"
  const eval = () => console.log('hello')    // Uncaught SyntaxError: 'eval' can't be defined or assigned to in strict mode code
})()

A New Scope For eval

It is possible to create variables in the caller's scope when calling eval in non-strict mode.

This pollution of the caller's scope is no longer possible when using strict mode. In strict mode, a new scope is created in which eval operates. And the scope is destroyed when eval returns.

Disabled 0-prefixed Octal Literals

In non-strict mode, you can prefix numbers with a zero, and JavaScript will interpret it as an octal number.

(function() {
  console.log(010)
})()
// 8

This 0-prefixed notation is disabled in strict mode, and the more robust notation with 0o (zero followed by the character o) can be used for octal literals.

(function() {
  console.log(0o10)
})()
// 8

The old syntax will lead to a syntax error in strict mode.

(function() {
  "use strict"
  console.log(010)
})()
// SyntaxError: "0"-prefixed octal literals and octal escape sequences are deprecated; for octal literals use the "0o" prefix instead

Removed with Statement

In sloppy mode, you can use the with statement.

(function() {
  const foo = { baz: {
    bar: {
      name: 'Tick',
      brothers: ['Trick', 'Track']
    }
  }}
  
  with(foo.baz.bar) {
    console.log(name)
    console.log(brothers)
  }
})()

// Tick
// ["Trick", "Track"]

When you run the same code but apply the "use strict" directive, you will get a SyntaxError instead.

(function() {
  "use strict"
  const foo = { baz: {
    bar: {
      name: 'Tick',
      brothers: ['Trick', 'Track']
    }
  }}
  
  with(foo.baz.bar) {
    console.log(name)
    console.log(brothers)
  }
})()

// SyntaxError: strict mode code may not contain 'with' statements

The with statement is considered harmful because the code was harder to reason about. It also caused hard to optimize performance issues. So the recommendation is to stay away from using the with statement, if you are in strict mode or not.

With modern JavaScript, there is no need to use the with statement anyway as you can use destructuring assignment when working with deeply nested objects.

(function() {
  const foo = { baz: {
    bar: {
      name: 'Tick',
      brothers: ['Trick', 'Track']
    }
  }}
  
  const { name, brothers } = foo.baz.bar
  console.log(name)
  console.log(brothers)
})()

  1. Run Eval Print Loop

Posted on CuteMachine.

Jo's Profile ImageWritten by Jo who lives and works in Frankfurt building digital doodah. Stalk him on Twitter.

TOS • Privacy • Disclaimer