The strict mode semantics are different from the traditional non-strict mode, which is sometimes called “sloppy mode”. In this mode, the syntax rules of the language are not so strict, and when some errors occur, the system does not notify the user about them. That is, errors can be ignored, and the code in which they are made can be executed further. This can lead to unexpected code execution results.
Strict mode introduces some changes to JavaScript semantics. It prevents the system from turning a blind eye to errors by throwing appropriate exceptions. This causes program execution to stop.
Strict mode, in addition, helps in writing programs in which there are no shortcomings that prevent JS engines from optimizing the code. Further, in this mode, the use of syntax elements is prohibited, which may get special meaning in future versions of the language.
Features of using strict mode
Strict mode can be applied to individual functions or to an entire script. It cannot be applied only to individual instructions or to blocks of code enclosed in curly braces. In order to use strict mode at the level of the whole script, at the very beginning of the file, before any other commands, you need to put the
"use strict"
or
'use strict'
construct.
If the project has some scripts that do not use strict mode, and others that use this mode, then it may happen that these scripts are merged.
This will lead to the fact that code that is not intended to be executed in strict mode will be in such a state when the system tries to execute it in strict mode. The reverse is also possible - code written for strict mode will fall into non-strict mode. Therefore, it is best not to mix “strict” and “non-strict” scripts.
As already mentioned, strict mode can be applied to individual functions. In order to do this
"use strict"
or
'use strict'
construct must be placed at the top of the function body, before any other commands. The strict mode with this approach applies to everything that is placed in the body of the function, including nested functions.
For example:
const strictFunction = ()=>{ 'use strict'; const nestedFunction = ()=>{ // } }
In JavaScript modules that appeared in the ES2015 standard, strict mode is enabled by default. Therefore, when working with them, you do not need to explicitly include it.
Changes introduced to JS code by strict mode
Strict mode affects both the syntax of the code and the way the code behaves during program execution. Errors in the code are converted to exceptions. The fact that in quiet mode quietly crashes in strict mode causes an error message. This is similar to how the system responds to syntax errors in lax mode. In strict mode, working with variables is simplified, the use of the
eval
function and the
arguments
object are tightly regulated, and work with constructs that can be implemented in future versions of the language is streamlined.
▍ Convert silent errors to exceptions
Silent errors are converted in strict mode to exceptions. In lax mode, the system does not explicitly respond to such errors. In strict mode, the presence of such errors leads to inoperability of the code.
So, thanks to this, it is difficult to make the mistake of accidentally declaring a global variable, since variables and constants in strict mode cannot be declared without using the
var
,
let
or
const
directives. As a result, creating variables without these directives will lead to program inoperability. For example, attempting to execute the following code will throw a
ReferenceError
exception:
'use strict'; badVariable = 1;
Such code cannot be run in strict mode, since if strict mode were turned off, it would create a global variable
badVariable
. Strict mode protects the programmer from inadvertently creating global variables.
An attempt to execute any code that, in normal mode, simply does not work, now throws an exception. Errors are considered to be any incorrect syntactic constructions that were simply ignored in lax mode.
So, for example, in strict mode, you cannot perform value assignment operations on read-only entities such as
arguments
,
NaN
or
eval
.
In strict mode, an exception, for example, will be thrown in the following cases:
- an attempt to assign a value to a read-only property, like some kind of rewritable global property;
- an attempt to write a value to a property that has only a getter;
- An attempt to write something to a property of a non-extensible object.
Here are examples of syntax constructs leading to strict mode exceptions:
'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;
Attempting to execute such code fragments in strict mode will throw a
TypeError
exception. For example,
undefined
and
Infinity
are global entities whose values cannot be overwritten, and the
foo
property of the
obj
object does not support rewriting. The
foo
property of
obj2
has only a getter. The
fixedObj
object
fixedObj
made non-extensible using the
Object.preventExtensions
method.
An attempt to delete an
TypeError
will also result in
TypeError
:
'use strict'; delete Array.prototype
Strict mode prohibits assigning properties with the same name to an object. As a result, an attempt to execute the following code will result in a syntax error:
'use strict'; let o = { a: 1, a: 2 };
Strict mode requires function parameter names to be unique. In non-strict mode, if, for example, two function parameters have the same name
one
, then, when passing the argument function, the parameter value will be what fell into the argument declared last.
In strict mode, parameters of functions with the same name are prohibited. As a result, an attempt to execute the following code will result in a syntax error:
'use strict'; const multiply = (x, x, y) => x*x*y;
In strict mode, you cannot use the octal notation of numbers, preceding the number with zero. This is not in the specification, but this feature is supported by browsers.
This state of affairs confuses developers, forcing them to believe that the 0 preceding the number is simply ignored, without much sense. In strict mode, trying to use a number at the beginning of which is 0 will result in a syntax error.
Strict mode also prohibits the use of structures that impede optimization. The interpreter, before performing code optimization, needs to know that the variable is stored exactly where, according to the interpreter, it is stored. In strict mode, things that interfere with optimizations are prohibited.
One example of such a ban concerns the
with
statement. If you use this instruction, this prevents the JS interpreter from finding out which variable or which property we are referring to, since it is possible that an entity with the same name exists both outside and inside the block of the
with
statement.
Suppose there is a code like this:
let x = 1; with (obj) { x; }
The interpreter will not be able to find out whether the variable
x
located inside the
with
block refers to the external variable
x
, or to the
obj.x
property of the
obj
object.
As a result, it is not clear exactly where the
x
value will be located in memory. In order to get rid of such ambiguities, the strict use of the
with
statement is prohibited. Let's see what happens if you try to execute the following code in strict mode:
'use strict'; let x = 1; with (obj) { x; }
The result of this attempt will be a syntax error.
Even in strict mode, it is forbidden to declare variables in the code passed to the
eval
method.
For example, in normal mode, a command of the form
eval('let x')
will result in the declaration of the variable
x
. This allows programmers to hide variable declarations in strings, which can lead to overwriting the definitions of the same variables outside of
eval
.
In order to prevent this, in strict mode it is forbidden to declare variables in the code that is passed as a string to the
eval
method.
Strict mode also prohibits the deletion of regular variables. As a result, attempting to execute the following code will result in a syntax error:
'use strict'; let x; delete x;
▍ Banning incorrect syntax constructs
In strict mode, the incorrect use of
eval
and
arguments
prohibited. This is a ban on all kinds of manipulations with them. For example, this is something like assigning new values to them, using their names as variable names, functions, function parameters.
Here are examples of misuse of
eval
and
arguments
:
'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;");
In strict mode, you cannot create aliases for the
arguments
object and set new
arguments
values through these aliases.
In normal mode, if the first parameter of the function is
a
, then setting the value of
a
in the function code also leads to a change in the value in
arguments[0]
. In strict mode,
arguments
will always contain the list of arguments with which the function was called.
Suppose you have the following code:
const fn = function(a) { 'use strict'; a = 2; return [a, arguments[0]]; } console.log(fn(1))
The console will get
[2,1]
. This is because writing a value of 2 to
a
does not write a value of 2 to
arguments[0]
.
▍Optimize performance
In strict mode, the
arguments.callee
property is not supported. In normal mode, it returns the name of the parent function of the function whose
callee
property of the
arguments
object we are examining.
Support for this property interferes with optimizations, such as embedding functions, since using
arguments.callee
requires the availability of a reference to a non-embedded function when accessing this property. In strict mode, using
arguments.callee
raises a
TypeError
exception.
In strict mode, the
this
does not have to always be an object. Under normal conditions, if
this
function is bound, using
call
,
apply
or
bind
, to something that is not an object, to a value of a primitive type like
undefined
,
null
,
number
or
boolean
, such a value should be an object.
If
this
context changes to something that is not an object, its place is taken by the global object. For example,
window
. This means that if you call a function by setting its
this
to a value that is not an object, instead of this value, a reference to the global object will fall into
this
.
Consider an example:
'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
console.log
commands will print
true
, because in strict mode the value of
this
in the function is not automatically replaced by a reference to the global object if
this
set to a value that is not an object.
▍ Security-related changes
In strict mode, you cannot make the
caller
and
arguments
function properties public. The fact is that
caller
, for example, can give access to the function that called the function whose
caller
property we are accessing.
The
arguments
object stores the arguments passed to the function when it was called. For example, if we have a function
fn
, this means that through
fn.caller
you can access the function that called the function, and using
fn.arguments
you can see the arguments passed to
fn
when it was called.
These features pose a potential security risk. As a result, access to these properties is prohibited in strict mode.
function secretFunction() { 'use strict'; secretFunction.caller; secretFunction.arguments; } function restrictedRunner() { return secretFunction(); } restrictedRunner();
In the previous example, we cannot, in strict mode, access
secretFunction.caller
and
secretFunction.arguments
. The fact is that these properties can be used to get a stack of function calls. If you try to run this code, a
TypeError
exception will be
TypeError
.
In strict mode, identifiers that may be used in future versions of JavaScript cannot be used to name variables or properties of objects. For example, we are talking about the following identifiers:
implements
,
interface
,
let
,
package
,
private
,
protected
,
public
,
static
and
yield
.
In ES2015 and in later versions of the standard, these identifiers became reserved words. And they cannot be used to name variables or properties in strict mode.
Summary
Strict mode is a standard that has existed for many years. It enjoys extremely broad browser support. Problems with strict-mode code can only occur in older browsers such as Internet Explorer.
Modern browsers should not have difficulty with strict JavaScript mode. As a result, we can say that this mode should be used to prevent “silent” errors and to improve application security. Silent errors are converted into exceptions that prevent the execution of programs, and in terms of improving security, you can, for example, mention strict-mode mechanisms that restrict
eval
and prevent access to the function call stack. In addition, the use of strict mode facilitates JS-engine code optimization and forces the programmer to carefully handle reserved words that may find use in future versions of JavaScript.
Dear readers! Do you use strict mode when writing JS code for your projects?