Why Do We Need Strict Mode in JavaScript?

What is it? What is it for? And why should we use it?

John Au-Yeung
Nov 10 · 8 min read
Photo by Pankaj Patel on Unsplash

Strict mode is an important part of modern JavaScript. It is a mode that lets us opt-in to a more restricted syntax of JavaScript.

The semantics of strict mode is different from the old “sloppy mode” of JavaScript that has a looser syntax and makes errors in code that are silenced. This means that errors are ignored and the code might run with unexpected results.

Strict mode makes several changes to JavaScript semantics. It eliminates silent errors and instead throws them so that the code won’t run with errors in the code.

It will also point out mistakes that prevent JavaScript engines from doing optimizations. Also, it prohibits features that are likely to be defined in future versions of JavaScript.

Strict mode can be applied to individual functions or the whole script. It can’t be applied only to statements or other blocks enclosed in curly braces. To make a script use strict mode, we add the statement "use strict" or 'use strict' at the top of the script before any other statements.

If we have some scripts that use strict mode and others that don’t, then we might have scripts that use strict mode that are concatenated with other scripts that don’t use strict mode.

This means that code that doesn’t use strict mode might have been made to use strict mode when it’s concatenated together. The reverse is also true. So, it’s best not to mix them together.

We can also apply this to functions. To do this, we add the statement "use strict" or 'use strict' inside the functions on the top of the body, before any other statements. It’s applied to everything inside, including functions that are nested in the function that uses strict mode.

For example:

const strictFunction = ()=>{
'use strict';
const nestedFunction = ()=>{
// this function also uses strict mode
}
}

JavaScript modules, introduced in ES2015, have strict mode automatically enabled, so no statement is needed to enable it.


Changes in Strict Mode


Converting Mistakes to Errors

It makes creating global variables hard by not letting us declare variables with var, let, or const, so creating variables without declaring them with those keywords won’t work. For example, the following code will throw a ReferenceError:

'use strict';
badVariable = 1;

We can’t run the code above in strict mode because this code will create a global variable badVariable if strict mode is off. Strict mode prevents this to prevent the creation of global variables accidentally.

Any code that silently fails will now throw an exception. This includes any invalid syntax that was ignored silently before.

For example, we can’t not assign to read-only variables like arguments, NaN, or eval with strict mode on.

Any assignment to read-only properties like non-writable global properties, assignment of getter-only properties, and assigning things to properties on non-extendable objects will throw an exception in strict mode.

Below are some examples of syntax that will fail with strict mode on:

'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;

All of the examples above will throw a TypeError. undefined and Infinity are non-writable global objects. obj is a non-writable property.

obj2’s foo property is a getter only property and so cannot be set. fixedObj was prevented from adding more properties to it with the Object.preventExtensions method.

Also, deleting undeletable properties will throw a TypeError when there is code attempting to do so. For example:

'use strict';
delete Array.prototype

This will throw a TypeError.

Strict mode also disallows duplicate property names in an object before ES6 is introduced, so the following example will throw a syntax error:

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

Strict mode requires that function parameter names are unique. Without strict mode, if two parameters have the name one, then the one defined later will be accepted as the parameter’s value when arguments are passed in.

With strict mode, having multiple function parameters with the same name is no longer allowed, so the following example will fail to run with a syntax error:

const multiply = (x, x, y) => x*x*y;

Octal syntax is also not allowed in strict mode. It isn’t part of the specification, but it’s supported in browsers by prefixing octal numbers with a 0.

This confuses developers as some may think that the 0 preceding the number is meaningless. Therefore, strict mode disallows this syntax and will throw a syntax error.

Strict mode also prevents the use of syntax that makes optimizations difficult. It needs to know that a variable is actually stored at the location that it thinks it’s stored at before doing optimization, so we have to prevent the kind of syntax that stops optimizations from happening.

One example of this is the with statement. If we use it, it prevents the JavaScript interpreter from knowing which variable or property you’re referring to, as it’s possible to have a variable with the same name inside or outside the with statement.

If we have something like the following code:

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

Then, JavaScript wouldn’t know if the x inside the with statement is referring to the x variable or the property of obj, obj.x.

Therefore, the memory location of x is ambiguous. So, strict mode prevents the with statement from being used. If we have strict mode like the following:

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

Then the code above will have a syntax error.

Another thing that strict mode prevents is the declaration of variables inside an eval statement.

For example, without strict mode, eval('let x') would declare the variable x into the code. This lets people hide variable declarations in strings that might override the same variable declaration that’s outside the eval statement.

To prevent this, strict mode disallows variable declarations in the string argument that we pass into an eval statement.

Strict mode also prohibits deletion of plain variable names, so the following will throw a syntax error:

'use strict';

let x;
delete x;

Prohibiting Invalid Syntax

This means that any manipulation done to them that isn’t allowed, like assigning new values to them or using them as names of variables, functions, or parameters in functions.

The following are examples of invalid uses of eval and the argument object that isn’t allowed:

'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;");

Strict mode doesn’t allow an alias for the arguments object to be created and set with new values via the alias.

Without strict mode, if the first parameter of a function is a, then setting a also sets arguments[0]. With strict mode, the arguments object will always have the list of arguments that the function is called with.

For example, if we have:

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

Then we should see [2,1] logged. This is because setting a to 2 doesn’t also set arguments[0] to 2.


Performance Optimizations

It prevents optimizations like inline functions because arguments.callee requires that a reference to the un-inlined function is available if arguments.callee is accessed. Therefore, with strict mode, arguments.callee now throws a TypeError.

With strict mode, this will not be forced into always being an object. If a function’s this is bound, with call, apply, or bind to any non-object type, like primitive types of undefined, null, number, boolean, etc, then they must be forced into being objects.

If the context of this is switched to a non-object type, then the global window object will take its place. This means that the global object is exposed to the function that’s being called with this being bound to non-object types.

For example, if we run the following code:

'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);

All the console logs will be true, as the this inside the function isn’t automatically converted into the window global object when this is changed to something that has a non-object type.


Security Fixes

The arguments have arguments that are passed in when the function is called. For example, if we have a function called fn, then through fn.caller, we can see the function that called fn, and through fn.arguments, we can see the arguments that were passed into fn when the call to fn is made.

This is a potential security hole that is eliminated by prohibiting access to these two properties of the function.

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

In the example above, we can’t access secretFunction.caller and secretFunction.arguments with strict mode as people may use it to get the call stack of functions. A TypeError will be thrown if we run that code.

Identifiers that will become restricted keywords in future versions of JavaScript will not be allowed to be used for identifiers like variable or property names.

The following keywords won’t be allowed to be used for defining our identifiers in code. implements, interface, let, package, private, protected, public, static, and yield.

With ES2015 or later, these have become reserved words, so they definitely cannot be used for naming variables and object properties without strict mode.

Strict mode has been a standard for a few years. Browser support for it is common, and only old browsers like Internet Explorer may have problems with it.

Other browsers shouldn’t have problems with working with strict mode. Therefore, it should be used to prevent mistakes and avoiding security hazards like exposing call stacks or declaring new variables in eval.

Also, it eliminates silent errors and instead throws them so that the code won’t run with errors in the code. It will also point out mistakes that prevent JavaScript engines to do optimizations.

Also, it prohibits features that are likely to be defined in future versions of JavaScript.

Better Programming

Advice for programmers.

John Au-Yeung

Written by

Web developer. Subscribe to my email list now at http://jauyeung.net/subscribe/ . Follow me on Twitter at https://twitter.com/AuMayeung

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade