Why is JavaScript required strict mode?

Strict mode is an important part of modern JavaScript. It is this mode that allows developers to use a more limited syntax than standard.



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:





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?








All Articles