preface

This article is from the advanced tutorial section of the MDN JavaScript topic. They cover inheritance and stereotypes, strict schemas, type arrays, memory management, concurrency models, and event loops. This is the second article on strict patterns.

Please click on me for the link to the original article


Here is the text:

Strict Mode in ECMAScript 5 allows you to quietly exit “sloppy Mode” by using a limited “variant” of JavaScript. The strict pattern is not just a subset of the normal pattern: it specifically has different semantics from the code in the normal pattern. If browser A does not support strict mode and browser B does, they will have different results running the same strict mode code, so don’t rely on strict mode code if you haven’t tested it properly. Strict and normal-mode code can coexist, so normal-mode code can be modified over time and eventually replaced with strict mode code.

Sometimes you’ll see a normal, non-strict mode called a “sloppy mode,” which isn’t exactly a technical term, but it’s always good to know.

Compared to normal mode, strict mode has the following changes in JavaScript semantics:

  1. Some hidden JavaScript bugs are eliminated and thrown out.
  2. Fixed some JavaScript bugs that make it difficult for the JavaScript engine to optimize code: sometimes code in strict mode executes faster than in normal mode.
  3. Syntactically disallow functionality that may appear in future versions of ECMAScript (such as disallowing the use of certain keywords).

If you want to change your code to work in this restricted variant of JavaScript, you can see migrate to Strict mode.


Enable Strict mode

Strict mode can be enabled at the global or function scope, but cannot be enabled separately in the block-level scope {}, where it has no effect if you try to enable it. ), windowtimers.setTimeout (); var timeoutID = scope.setTimeout(code[, delay]); Code, and the like are globally scoped, where strict mode can also be enabled.

Global scopeUnder strict mode

To enable strict mode in the global scope, simply write “use strict” before any other code; (or ‘use strict’;) .

// Strict schema syntax for global scope
'use strict';
var v = "Hi! I'm a strict mode script!";
Copy the code

There is a trap in this syntax that affects a major web site: two scripts that conflict cannot be combined. For example, if you need to merge a normal-mode script into a strictly mode script, the entire script becomes strictly mode! This, in turn, becomes a normal-mode script. Obviously, merging scripts is never a good idea, and if you must do so, enable it separately for each function scope.

You can also put the entire contents of the script in a function and decide whether to enable strict mode or not. This eliminates the merge problem and also means that you have to manually export variables from functions that need to be shared.

Function scopeUnder strict mode

Similarly, to enable strict mode in a function scope, write “use strict” before any code in the function body; (or ‘use strict’;) .

function strict() {
  // Strict schema syntax for function scope
  'use strict';
  function nested() { return 'And so am I! '; }
  return "Hi! I'm a strict mode function! " + nested();
}
function notStrict() { return "I'm not strict."; }
Copy the code

Strict mode under modules

ECMAScript 2015 introduced JavaScript modules, so there’s now a third way to enable strict mode. The code in the JavaScript module automatically turns on strict mode without any declaration.

function strict() {
    // Because this function is in the module, the code automatically enables strict mode
}
export default strict;
Copy the code

Some changes in strict mode

Strict mode changes both syntax and runtime behavior. Change can be divided into the following categories:

  1. Turn some mistakes into errors (syntax errors or runtime errors)
  2. Simplified mapping of variable names to specific variables
  3. To simplify theevalandargumentsThe use of
  4. Easier to write “secure JavaScript”
  5. Set the stage for future ECMAScript evolution.

Turn misunderstandings into mistakes

In strict mode, previously widely accepted misunderstandings are turned into errors. JavaScript is a newbie friendly development language, and sometimes what should be wrong operations are given non-wrong semantics. This can solve some problems temporarily, but sometimes it also stores up even worse problems for the future. Strict mode allows these bad operations to become run-time errors that can be found and resolved in a timely manner.

First, strict mode forbids the accidental creation of global variables. In regular JavaScript, if a variable is mistakenly entered during assignment, it becomes a property of the global object and the program continues to “work as usual” (though it may fail in future versions of JavaScript). In strict mode, assigning to an undefined variable does not create a global variable, but throws an error:

'use strict';
                       // Assume that mistypeVariable does not exist
mistypeVariable = 17;  // This line throws a ReferenceError because the variable name was misspelled.
Copy the code

Second, in strict mode, some assignments that were previously invalid will now throw an exception. For example, NaN is a global variable that is not writable. Nothing happens when you assign to NaN in normal mode, and the developer does not receive any error feedback. Doing so in strict mode throws an exception. In strict mode, any assignment that is invalid in normal mode (such as assigning to an unwritable global variable or object property, assigning to a read-only object property, adding a new property to an unextensible object) will throw an exception in strict mode:

'use strict';

// Assign to an unwritable global variable
var undefined = 5; / / throw TypeError
var Infinity = 5; / / throw TypeError

// Assign to an object property that is not writable
var obj1 = {};
Object.defineProperty(obj1, 'x', { value: 42.writable: false });
obj1.x = 9; / / throw TypeError

// Assign to a read-only object property
var obj2 = { get x() { return 17; }}; obj2.x =5; / / throw TypeError

// Add a new attribute to an unextensible object
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = 'ohai'; / / throw TypeError
Copy the code

Third, strict mode will also throw an exception if an attempt is made to remove a non-deletable attribute (just not in normal mode) :

'use strict';
delete Object.prototype; / / throw TypeError
Copy the code

Fourth, in the strict pattern prior to Gecko 34, all object literals were required to have unique properties defined. In normal mode, you just copy one attribute, and the last attribute determines the final value. Since only the last property of the same name is active, such copying can cause a cascade of bugs if the property value is changed instead of the last property itself. Repeating attributes in strict mode is a syntax error:

Note: Redefining attributes is allowed after ECMAScript 2015 (Bug 1041128)

'use strict';
var o = { p: 1.p: 2 }; / /!!!!!! syntax error
Copy the code

Fifth, strict mode requires that function parameter names be unique. In normal mode, the last argument overrides the previous ones, but they are not completely inaccessible and can still be retrieved using arguments[I]. However, this overwriting is meaningless and may even be unintentional (it may just be a spelling mistake, for example), so it is a grammatical error in strict mode:

function sum(a, a, c) { / /!!!!!! syntax error
  'use strict';
  return a + a + c; // The code is running in error
}
Copy the code

Sixth, strict mode disallows octal syntax. Octal syntax is not the ECMAScript standard, but is supported by all browsers (simply prefix an octal number with 0:06 44 === 420, or “\045” === “%”). Octal numbers can be made in ECMAScript 2015 by adding 0o, for example:

var a = 0o10; // ES2015: octal
Copy the code

Novice developers may think 0 as a prefix doesn’t mean anything, so they use 0 for code alignment, but this changes the actual value of the number! Prefixes with 0 are almost useless and misleading, so in strict mode this will result in syntax errors:

'use strict';
var sum = 015 + / /!!!!!! syntax error
          197 +
          142;

var sumWithOctal = 0o10 + 8;
console.log(sumWithOctal); / / 16
Copy the code

Seventh, strict mode forbids adding attributes to underlying type values, whereas normal mode simply does not. Strict mode raises TypeError:

(function() {
'use strict';

false.true = ' ';         // TypeError
(14).sailing = 'home';   // TypeError
'with'.you = 'far away'; // TypeError}) ();Copy the code

Simplify the use of variables

The strict pattern simplifies the mapping between variable names and specific variable definitions in the code. Some optimizations by the compiler rely on quickly finding out where a variable is stored, which is critical to optimizing JavaScript code across the board. Sometimes this mapping is not established until runtime. Strict schema eliminates most of the conditions that affect the establishment of mapping relationships, so the compiler can better optimize strict schema code.

First, strict mode prohibits the use of with. The problem with with is that any variable names in its code block map either to the object attributes passed to it or to its external (possibly global) scoped variables, and the mapping can only be established at run time and cannot be known in advance. Strict mode makes with a syntactic error to avoid the problem of variable names in their blocks not being positioned before the code runs:

'use strict';
var x = 17;
with (obj) { / /!!!!!! syntax error
  // If not in strict mode, x refers to externally defined 'var x'?
  // obj. X? We don't know for sure until the code actually runs,
  // So this code cannot be optimized
  x;
}
Copy the code

A simple alternative is to temporarily store the object in a variable and then access the corresponding attribute of the variable instead of using with.

Second, variables declared in eval in strict mode do not leak into their surrounding scopes. In normal mode eval(“var x; ) introduces the variable x in its surrounding scope (function or global scope). This means that, in general, in functions with eval calls, the variable names of non-parameter or local variables must also wait until the runtime can map to concrete variables (because eval calls may introduce new variables to override external variables). In strict mode eval creates variables only for code passed into it for parsing, so external or local variables are not affected:

Translator’s Note:

Second, eval of strict mode code does not introduce new variables into the surrounding scope. In normal code eval(“var x;” ) introduces a variable x into the surrounding function or the global scope. This means that, in general, in a function containing a call to eval every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because that eval might have introduced a new variable that would hide the outer variable). In strict mode eval creates variables only for the code being evaluated, so eval can’t affect whether a name refers to an outer variable or some local variable:

This can be a bit of a mouthful, but in a nutshell, eval is called in a function. There are three types of variable references in a function, the first being locally defined variables, the second being function parameter variables, and the third being external variables (the external scope may still be function, or global scope). For the first two types of variables, the mapping must wait until the function is executed, but for the third, the value is normally determined at function declaration, and because of the leakage of variables introduced into eval, the value is changed if the leaked variables are external variables. This results in a third value mapping that has to wait until the function is executed! The outer variable is the outer variable.

var x = 17;
var evalX = eval("'use strict'; var x = 42; x;");
console.assert(x === 17);
console.assert(evalX === 42);
Copy the code

If, in strict schema code, the eval function starts with eval(…) This expression form is called, and the string passed into it is parsed into strict schema code and executed. It is also possible to explicitly declare strict mode on the passed string, but this is not necessary:

function strict1(str) {
  'use strict';
  return eval(str); // STR is treated as strictly modal code
}
function strict2(f, str) {
  'use strict';
  return f(str); / / not ` eval (...). Only if STR explicitly declares strict mode,
                 // STR is considered strictly mode code
}
function nonstrict(str) {
  return eval(str); // Only by explicitly declaring strict mode in STR,
                    // STR is considered strictly mode code
}

strict1("'Strict mode code! '");
strict1("'use strict'; 'Strict mode code! '");
strict2(eval."'Non-strict code.'");
strict2(eval."'use strict'; 'Strict mode code! '");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code! '");
Copy the code

Thus, variables in strict mode code executed in EVAL behave the same as variables in code that is not executed in strict mode.

Third, strict mode forbids deleting a single variable name. Delete name is a syntax error in strict mode:

'use strict';

var x;
delete x; / /!!!!!! syntax error

eval('var y; delete y; '); / /!!!!!! syntax error
Copy the code

makeevalandargumentsMore simple

Eval can add and remove bindings, and arguments can change binding values, and Arguments can alias function arguments using its index attribute name. Strict mode makes great strides in treating Eval and arguments as keywords, although full fixes won’t come until a future version of ECMAScript.

First, at the syntactically level, eval and arguments cannot be bound or assigned. All of these operations will be syntax errors:

'use strict';
eval = 17;
arguments+ +; ++eval;
var obj = { set p(arguments) {}};var eval;
try{}catch (arguments) {}function x(eval) {}function arguments() {}var y = function eval() {};var f = new Function('arguments'."'use strict'; return 17;");
Copy the code

Second, the index attribute of the Arguments object is no longer used as an alias for function arguments. In regular mode functions, changing arg affects arguments[0] if the function’s first argument is arg, and vice versa (unless there are no arguments or arguments[0] is removed). The Arguments object in a strict mode function stores the original arguments when the function is called. Arguments [I] no longer tracks changes in the value of the corresponding named parameter, and this named parameter no longer tracks changes in the value of arguments[I].

function f(a) {
  'use strict';
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
console.assert(pair[0= = =42);
console.assert(pair[1= = =17);
Copy the code

Third, arguments.callee is no longer supported. In regular functions, arguments.callee refers to the function itself. It doesn’t make sense: just name the function itself and use that name! In addition, arguments.callee is a serious impediment to compiler optimizations such as inlining functions, since accessing arguments.callee requires maintaining a reference to that function so that it cannot be inlined. In strict mode, calling within a function or setting arguments.callee will result in an error, and it is also a non-deletable property:

'use strict';
var f = function() { return arguments.callee; };
f(); / / throw TypeError
Copy the code

“Secure” JavaScript

Strict mode makes it easier to write “safe” JavaScript. Some web sites now offer users a way to write JavaScript that the site can then run on behalf of other users. JavaScript in a browser can ask the user for private information, so this type of JavaScript must undergo some transformation before execution to check whether it has access to some prohibited function. The flexible nature of JavaScript makes this review virtually impossible without a lot of runtime checking. The functionality of some languages is so pervasive that performing runtime checks can be a significant performance drain. Part of strict mode reverses this situation, along with requiring user-submitted JavaScript code to be in strict mode so that it can be invoked with some validation, greatly reducing the need for runtime checking.

First, the value of this in a function is no longer mandatory to be an object (called “boxed”). In normal-mode functions, this is always the object: Either the object bound to this when called, the wrapper object (if string, bool, and number), or the global object (if undefined or NULL is passed) (you can specify the object bound to this using call, apply, or bind). Not only does automatic wrapping have a performance cost, but it also has security implications for exposing the browser’s global objects (because global objects provide some functionality that a “safe” JavaScript environment must constrain). So in strict mode functions, this is not automatically wrapped as an object, and if not specified, this is undefined.

'use strict';
function fun() { return this; }
console.assert(fun() === undefined);
console.assert(fun.call(2) = = =2);
console.assert(fun.apply(null) = = =null);
console.assert(fun.call(undefined) = = =undefined);
console.assert(fun.bind(true) () = = =true);
Copy the code

This means that you can no longer use this to access window objects in strictly patterned functions.

Second, in strict mode, the JavaScript code stack can no longer be traced through the usual extensions in ECMAScript. In the normal pattern, fun is assumed to be called midway through the call. With these extensions, for example, fun.caller can get the function that recently called Fun, and fun.arguments can get the function arguments for that call. These extensions can compromise “secure” JavaScript code because they allow “secure” code access to proprietary functions and their (potentially unprotected) arguments. If fun is in strict mode, fun.caller and fun.arguments are non-deletable properties, and both reading and setting them will throw an error.

function restricted() {
  'use strict';
  restricted.caller;    / / throw TypeError
  restricted.arguments; / / throw TypeError
}
function privilegedInvoker() {
  return restricted();
}
privilegedInvoker();
Copy the code

Third, Arguments in strict mode no longer provides local variable access to the currently called function. In some older implementations of ECMAScript versions, properties on arguments. Caller objects can be used as aliases for local variables in that function call. This is a security vulnerability because it breaks the ability to hide private variables through function abstraction, and it also hinders most compiler optimizations. For these reasons, none of today’s browsers implement it. As of now, due to these history features of Arguments. caller, it is also a non-deletable property in strict mode, and can be set or read with an error.

'use strict';
function fun(a, b) {
  'use strict';
  var v = 12;
  return arguments.caller; / / throw TypeError
}
fun(1.2); // Does not expose v (or A and B)
Copy the code

Pave the way for future ECMAScript

ECMAScript 5’s strict schema uses some restrictions to make the transition smoother. If some future change basis is already prohibited in strict mode, it will be easier for those changes to advance in the new release.

First, in strict mode, a small number of identifiers become reserved keys. These include: implements, Interface, let, Package, private, protected, public, static, and yield. In strict mode, you cannot use these for variable or parameter naming.

function package(protected) { / /!!!!!!
  'use strict';
  var implements; / /!!!!!!

  interface: / /!!!!!!
  while (true) {
    break interface; / /!!!!!!
  }

  function private() {}/ /!!!!!!
}
function fun(static) { 'use strict'; } / /!!!!!!
Copy the code

There are two caveats for Mozilla: First, if your JavaScript version is 1.7 or greater (e.g., your Chrome code or the correct use of loaded, you cannot use the let/yield identifier. Second, while ES5 retains class, enum, extends, import, and super unconditionally, Mozilla retained them only in strict mode prior to Firefox 5.

Second, strict mode prohibits function declarations outside the global or function top-level. In normal mode browsers, function declarations are allowed “anywhere”. * This is not an ES5 (or even ES3) specification! * It is a syntactic extension and is semantically incompatible across browsers. Note that ECMAScript 2015 allows function declarations outside the top layer.

'use strict';
if (true) {
  function f() {}/ /!!!!!! syntax error
  f();
}

for (var i = 0; i < 5; i++) {
  function f2() {}/ /!!!!!! syntax error
  f2();
}

function baz() { / / legal
  function eit() {}/ / is legal
}
Copy the code

This prohibition is not exactly strict mode, because allowing function declarations “anywhere” is a syntactic extension of ES5. But the ECMAScript committee recommended this syntax extension, so browsers implement it.

Strict mode in the browser

The major browsers now implement strict mode. However, there are still many versions of browsers that support strict mode only partially or not at all (IE10 and below, for example). Strict patterns change the semantics of the code. Depending on these changes can lead to misunderstandings or errors if the browser does not support strict mode. Be careful when using strict mode. Before relying on strict mode, make sure you have unit tests to verify that the relevant parts of strict mode code are working properly. Finally, make sure you test your code in both browsers that support strict patterns and browsers that don’t. If you test your code only in browsers that don’t support strict patterns, you may run into problems in browsers that do, and vice versa.

specification

ECMAScript (ECMA-262)

The definition of ‘Strict Mode Code’ in that specification.

Refer to the article

  • Where’s Walden? » New ES5 strict mode support: now with poison pills!
  • Where’s Walden? » New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited
  • Where’s Walden? » New ES5 strict mode support: new vars created by strict mode eval code are local to that code only
  • JavaScript “use strict” tutorial for beginners.
  • John Resig – ECMAScript 5 Strict Mode, JSON, and More
  • ECMA-262-5 in detail. Chapter 2. Strict Mode.
  • Strict mode compatibility table
  • Transitioning to strict mode