Strict mode

In addition to the normal operating mode, JavaScript has a second operating mode: strict mode. As the name suggests, this mode uses a stricter JavaScript syntax.

The same code may have different results in normal mode and strict mode. Some statements that can be run in normal mode cannot be run in strict mode.

Aim of design

The early JavaScript language had many unreasonable designs, but in order to be compatible with the previous code, and the old grammar could not be changed, new grammars could only be added continuously to guide programmers to use new grammars.

Strict mode entered the standard from ES5, and the main purposes are as follows.

-Explicitly prohibit some unreasonable and imprecise syntax, and reduce some weird behaviors of the JavaScript language. -Add more occasions for reporting errors, eliminate some insecure aspects of code operation, and ensure the safety of code operation. -Improve the efficiency of the compiler and increase the running speed. -Pave the way for the new version of JavaScript syntax in the future.

In short, strict mode embodies the development direction of JavaScript that is more reasonable, safer, and more rigorous.

How to enable

The sign to enter strict mode is a one-line string use strict.

"use strict";

Older versions of the engine will treat it as a normal string and ignore it. The new version of the engine will enter strict mode.

Strict mode can be used for the entire script or only for a single function.

(1) The entire script file

Put use strict on the first line of the script file, and the entire script will run in strict mode. If this line of statement is not in the first line, it is invalid, and the entire script will run in normal mode. (Strictly speaking, as long as the preceding statement is not the statement that produces the actual running result, use strict can not be on the first line, such as directly after an empty semicolon, or after a comment.)

<script>
  "use strict";
  console.log("This is strict mode");
</script>

<script>
  console.log("This is normal mode");
</script>

In the above code, a web page file has two pieces of JavaScript code in turn. The former <script> tag is in strict mode, the latter is not.

If use strict is written as follows, it will not work. Strict mode must take effect from the beginning of the code.

<script>
  console.log("This is normal mode");
  ("use strict");
</script>

(2) Single function

Put use strict on the first line of the function body, and the entire function runs in strict mode.

function strict() {
  "use strict";
  return "This is strict mode";
}

function strict2() {
  "use strict";
  function f() {
    return "This is also strict mode";
  }
  return f();
}

function notStrict() {
  return "This is normal mode";
}

Sometimes, different scripts need to be combined in one file. If one script is in strict mode and the other is not, their merging may go wrong. If the strict mode script comes first, the merged scripts are all strict mode; if the normal mode script comes first, the merged scripts are all normal mode. In both cases, the combined result is incorrect. At this time, you can consider putting the entire script file in an anonymous function that is executed immediately.

(function () {
  "use strict";
  // some code here
})();

Explicitly report errors

Strict mode makes the syntax of JavaScript more strict, and more operations will explicitly report errors. Some of these operations will fail silently in normal mode, and no error will be reported.

Read-only attributes are not writable

In strict mode, if you set the length property of a string, an error will be reported.

"use strict";
"abc".length = 5;
// TypeError: Cannot assign to read only property'length' of string'abc'

The above code reports an error because length is a read-only property and cannot be written in strict mode. In normal mode, changing the length property is invalid, but no error will be reported.

In strict mode, assigning a value to a read-only attribute or deleting a non-configurable attribute will cause an error.

// Assign a value to a read-only attribute will report an error
"use strict";
Object.defineProperty({}, "a", {
  value: 37,
  writable: false,
});
obj.a = 123;
// TypeError: Cannot assign to read only property'a' of object #<Object>

// Deleting non-configurable properties will report an error
("use strict");
var obj = Object.defineProperty({}, "p", {
  value: 1,
  configurable: false,
});
delete obj.p;
// TypeError: Cannot delete property'p' of #<Object>

Only set the value of the attribute can not be written

In strict mode, an error will be reported when assigning a value to a property that has only a getter but no setter.

"use strict";
var obj = {
  get v() {
    return 1;
  },
};
obj.v = 2;
// Uncaught TypeError: Cannot set property v of #<Object> which has only a getter

In the above code, obj.v only has a value device, and there is no value device. If you assign a value to it, an error will be reported.

Objects that are forbidden to extend cannot be extended

In strict mode, adding new attributes to objects that are forbidden to extend will cause an error.

"use strict";
var obj = {};
Object.preventExtensions(obj);
obj.v = 1;
// Uncaught TypeError: Cannot add property v, object is not extensible

In the above code, the obj object is forbidden to expand, and an error will be reported when adding attributes.

eval, arguments cannot be used as identifiers

In strict mode, if you use eval or arguments as the identifier, an error will be reported. The following statements will report errors.

'use strict';
var eval = 17;
var arguments = 17;
var obj = {set p(arguments) {} };
try {} catch (arguments) {}
function x(eval) {}
function arguments() {}
var y = function eval() {};
var f = new Function('arguments', "'use strict'; return 17;");
// SyntaxError: Unexpected eval or arguments in strict mode

Function cannot have parameters with the same name

In normal mode, if the function has multiple parameters with the same name, you can use arguments[i] to read them. In strict mode, this is a grammatical error.

function f(a, a, b) {
  "use strict";
  return a + b;
}
// Uncaught SyntaxError: Duplicate parameter name not allowed in this context

Prohibit octal prefix 0 notation

In normal mode, if the first digit of an integer is 0, it means that it is an octal number, for example, 0100 is equal to 64 in decimal. Strict mode prohibits this notation, the first digit of the integer is 0, and an error will be reported.

"use strict";
var n = 0100;
// Uncaught SyntaxError: Octal literals are not allowed in strict mode.

Enhanced security measures

Strict mode enhances security protection and prevents some accidental errors from the syntax.

Explicit declaration of global variables

In normal mode, if a variable is assigned without declaration, the default is a global variable. Strict mode prohibits this usage, and global variables must be declared explicitly.

"use strict";

v = 1; // An error is reported, v is not declared

for (i = 0; i < 2; i++) {
  // error, i is not declared
  // ...
}

function f() {
  x = 123;
}
f(); // Error, create a global variable without declaration

Therefore, in strict mode, variables must be declared first and then used.

Prohibit this keyword from pointing to global objects

In normal mode, this inside the function may point to the global object. Strict mode prohibits this usage to avoid inadvertently creating global variables.

// normal mode
function f() {
  console.log(this === window);
}
f(); // true

// strict mode
function f() {
  "use strict";
  console.log(this === undefined);
}
f(); // true

In the above code, this inside the function body in strict mode is undefined.

This restriction is especially useful for constructors. When using the constructor, sometimes I forgot to add new. At this time, this no longer points to the global object, but an error is reported.

function f() {
  "use strict";
  this.a = 1;
}

f(); // An error is reported, this is not defined

In strict mode, when the function is called directly (without calling new), the this inside the function means undefined (undefined), so you can use the call, apply and bind methods to change any The value is bound to this. In normal mode, this points to the global object. If the bound value is a non-object, it will be automatically converted to an object and then bound. However, the two values ​​of null and undefined that cannot be converted into object values ​​will be ignore.

// normal mode
function fun() {
  return this;
}

fun(); // window
fun.call(2); // Number {2}
fun.call(true); // Boolean {true}
fun.call(null); // window
fun.call(undefined); // window

// strict mode
("use strict");
function fun() {
  return this;
}

fun(); //undefined
fun.call(2); // 2
fun.call(true); // true
fun.call(null); // null
fun.call(undefined); // undefined

In the above code, you can bind any type of value to this.

Prohibit the use of fn.callee, fn.caller

fn.caller and fn.arguments must not be used inside the function, otherwise an error will be reported. This means that the call stack cannot be obtained inside the function.

function f1() {
  "use strict";
  f1.caller; // report an error
  f1.arguments; // error
}

f1();

Prohibit the use of arguments.callee, arguments.caller

arguments.callee and arguments.caller are two variables left over from history. They have never been standardized, and they are now cancelled. Calling them in normal mode has no effect, but no error will be reported. Strict mode clearly stipulates that using arguments.callee and arguments.caller inside the function will report an error.

"use strict";
var f = function () {
  return arguments.callee;
};

f(); // error

Prohibit deleting variables

Variables cannot be deleted in strict mode. If you use the delete command to delete a variable, an error will be reported. Only the properties of the object, and the property description object's configurable property is set to true, can it be deleted by the delete command.

'use strict';
var x;
delete x; // syntax error

var obj = Object.create(null, {
  x: {
    value: 1,
    configurable: true
  }
});
delete obj.x; // Delete successfully

Static binding

A feature of the JavaScript language is that it allows "dynamic binding", that is, which object certain properties and methods belong to is not determined at compile time, but at runtime.

Strict mode imposes some restrictions on dynamic binding. In some cases, only static binding is allowed. In other words, which object the attributes and methods belong to must be determined at the compilation stage. This is conducive to the improvement of compilation efficiency, but also makes the code easier to read, and there are fewer accidents.

Specifically, the following aspects are involved.

The with statement is prohibited

In strict mode, using the with statement will report an error. Because the with statement cannot be determined at compile time, which object a certain attribute belongs to, which affects the compilation effect.

"use strict";
var v = 1;
var obj = {};

with (obj) {
  v = 2;
}
// Uncaught SyntaxError: Strict mode code may not include a with statement

Create eval scope

In normal mode, JavaScript language has two variable scopes (scope): global scope and function scope. Strict mode creates a third scope: the eval scope.

In normal mode, the scope of the eval statement depends on whether it is in the global scope or the function scope. In strict mode, the eval statement itself is a scope, and it is no longer possible to create new variables in the scope in which it is run. That is to say, the variables generated by eval can only be used inside eval.

(function () {
  "use strict";
  var x = 2;
  console.log(eval("var x = 5; x")); // 5
  console.log(x); // 2
})();

In the above code, since the inside of the eval statement is an independent scope, the internal variable x will not leak to the outside.

Note that if you want the eval statement to also use strict mode, there are two ways.

// method one
function f1(str) {
  "use strict";
  return eval(str);
}
f1("undeclared_variable = 1"); // report an error

// Method two
function f2(str) {
  return eval(str);
}
f2('"use strict";undeclared_variable = 1'); // error

In the above two ways, eval uses strict mode internally.

arguments no longer track changes in parameters

The variable arguments represents the parameters of the function. In strict mode, the connection between changing the parameters inside the function and arguments is cut off, and there is no longer a linkage relationship between the two.

function f(a) {
  a = 2;
  return [a, arguments[0]];
}
f(1); // Normal mode is [2, 2]

function f(a) {
  "use strict";
  a = 2;
  return [a, arguments[0]];
}
f(1); // strict mode is [2, 1]

In the above code, changing the parameters of the function will not reflect the arguments object.

Transition to the next version of JavaScript

The next version of the JavaScript language is ECMAScript 6. For a smooth transition, strict mode introduces some ES6 syntax.

Non-function code blocks must not declare functions

ES6 will introduce block-level scope. In order to keep up with the new version, ES5's strict mode only allows functions to be declared in the global scope or function scope. In other words, it is not allowed to declare functions in non-function code blocks.

"use strict";
if (true) {
  function f1() {} // syntax error
}

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

The above code declares functions in the if code block and the for code block, and the ES5 environment will report an error.

Note that if it is an ES6 environment, the above code will not report an error, because ES6 allows functions to be declared in the code block.

Reserved words

In order to transition to the new version of JavaScript in the future, strict mode adds some reserved words (implements, interface, let, package, private, protected, public, static, yield, etc.). Using these words as variable names will give an error.

function package(protected) {
  // syntax error
  "use strict";
  var implements; // syntax error
}