preface
Strict mode is introduced in ES5 to eliminate some syntax errors, improve runtime efficiency, and standardize JavaScript syntax.
The differences between strict mode and non-strict mode are carefully sorted out in this paper for the purpose of deepening the understanding of strict mode.
open
The script file
Enable strict mode for the script file. The first script does not enable strict mode. The second script will enable strict mode.
<body>
<script>
foo = 33
console.log(window.foo) / / 33
</script>
<script>
'use strict'
bar = 33 // Uncaught ReferenceError: bar is not defined
</script>
</body>
Copy the code
Note that in addition to comments in the code, ‘use strict’ must be at the beginning of the script, otherwise it will not take effect
function
Turn on strict mode for functions.
function fn() {
'use strict'. }Copy the code
In addition, if a function parameter specifies a default value, uses destruct or residual parameters, the function will not display the declaration strict mode internally, otherwise an error will be reported.
function fn(first = 1) { // Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list
'use strict'
}
function fn({ foo }) {
'use strict'
}
function fn(. rest) {
'use strict'
}
Copy the code
So why do these three cases report errors?
‘Use strict’ means that both function parameters and function body are executed in strict mode. Note that the function executes the parameters first, and then the function body.
What is not reasonable is that the strict mode is specified inside the function, and at run time, the parameters have no way of determining which mode to run because the function body has not been executed.
In ES5, the V8 engine considered delayed error reporting, that is, parsing the function body before determining whether the parameters meet the strict mode, but this caused performance problems and added complexity, so it was completely disabled.
The solution is as simple as thinking about how to turn parameters on in strict mode. The first is to turn on strict mode globally.
The second approach uses self-executing functions to form closure structures.
var fn = (function () {
'use strict'
return function (first = 1) {... }}) ()Copy the code
variable
Creating global variables
Non-strict mode, will be created as a global variable.
foo = 22
console.log(window.foo) / / 22
Copy the code
Strict mode, no longer can accidentally create global variables.
'use strict'
foo = 22 // Uncaught ReferenceError: foo is not defined
console.log(window.foo)
Copy the code
To delete a variable
In non-strict mode, deleting variables allows operations, but does not take effect.
var foo = 22
delete foo
console.log(foo) / / 22
Copy the code
In strict mode, deleting a variable throws an error.
'use strict'
var foo = 22
delete foo // Uncaught SyntaxError: Delete of an unqualified identifier in strict mode
console.log(foo)
Copy the code
Reserved keywords
Non-strict mode that allows keywords as variable names.
var let = 22
console.log(let) / / 22
Copy the code
Strict schema disallows implements, interface, let, package, private, protected, public, static, and yield as variable names.
'use strict'
var let = 22 // Uncaught SyntaxError: Unexpected strict mode reserved word
console.log(let)
Copy the code
Octal value
Non-strict mode that allows octal values starting with 0.
var foo = 012
console.log(foo) / / 10
Copy the code
Strict mode disallows octal values starting with 0. In ES6, octal values can be declared with either 0O or 0O.
'use strict'
var foo = 012 // Uncaught SyntaxError: Octal literals are not allowed in strict mode
console.log(foo)
Copy the code
eval / arguments
Non-strict mode that allows modification of assignments to the keywords eval and arguments.
var eval = 22
console.log(eval) / / 22
function fn(arguments) {
console.log(arguments) / / 3
}
fn(3)
Copy the code
Strict mode disallows changing assignments to the keywords eval and arguments.
'use strict'
var eval = 22 // Uncaught SyntaxError: Unexpected eval or arguments in strict mode
console.log(eval)
'use strict'
function fn(arguments) { // Uncaught SyntaxError: Unexpected eval or arguments in strict mode
console.log(arguments)
}
fn(3)
Copy the code
summary
- You cannot accidentally create global variables
- You can’t use
delete
To delete a variable - It is prohibited to use
implements
,interface
,let
,package
,private
,protected
,public
,static
andyield
And other keywords as variable names - ban
0
Octal number at the beginning - Disallow the keyword
eval
andarguments
Modify the assignment
object
Attribute assignment
In non-strict mode, assignments to read-only and unmodifiable properties on an object do not take effect.
const foo = { get x() { return 1 } }
foo.x = 5
console.log(foo) // {x: 1}
const bar = {}
Object.defineProperty(bar, 'x', {
value: 2.writable: false
})
bar.x = 6
console.log(bar) // {x: 2}
Copy the code
In strict mode, an error is thrown on assignment.
'use strict'
const foo = { get x() { return 1 } }
foo.x = 5 // Uncaught TypeError: Cannot set property x of #<Object> which has only a getter
console.log(foo)
'use strict'
const bar = {}
Object.defineProperty(bar, 'x', {
value: 2.writable: false
})
bar.x = 6 // Uncaught TypeError: Cannot assign to read only property 'x' of object '#<Object>'
console.log(bar)
Copy the code
Delete the properties
Non-strict mode, cannot be configured Attribute deletion does not take effect.
const foo = {}
Object.defineProperty(foo, 'x', { value: 2.configurable: false })
delete foo.x
console.log(foo) // {x: 2}
Copy the code
In strict mode, an error occurs when the unconfigurable property is deleted.
'use strict'
const foo = {}
Object.defineProperty(foo, 'x', { value: 2.configurable: false })
delete foo.x // Uncaught TypeError: Cannot delete property 'x' of #<Object>
console.log(foo)
Copy the code
Add attributes
In non-strict mode, adding attributes to non-extensible objects does not take effect.
const foo = {}
Object.preventExtensions(foo)
foo.x = 2
console.log(foo) / / {}
Copy the code
Strict mode, adding attributes to an unextensible object will cause an error.
'use strict'
const foo = {}
Object.preventExtensions(foo)
foo.x = 2 // Uncaught TypeError: Cannot add property x, object is not extensible
console.log(foo)
Copy the code
summary
- An error is thrown when assigning read-only and unmodifiable attributes
- An error is thrown when the unconfigurable property is modified
- An error is thrown when attributes are added to an unextensible object
function
Parameter to repeat
Non-strict mode, parameter names can be repeated.
function fn(foo, foo, bar) {
console.log(foo, foo, bar) / / 2, 2, 3
}
fn(1.2.3)
Copy the code
Strict mode that requires the parameter name to be unique.
'use strict'
function fn(foo, foo, bar) { // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
console.log(foo, foo, bar)
}
fn(1.2.3)
Copy the code
Arguments to parameters
Non-strict mode, arguments are strictly bound to the parameter.
function fn(foo) {
foo = 22
console.log(foo, [...arguments]) / / 22 [22, 2)
arguments[0] = 99
console.log(foo, [...arguments]) / / 99/99, 2
}
fn(1.2)
Copy the code
In strict mode, arguments are no longer bound to parameters.
'use strict'
function fn(foo) {
foo = 22
console.log(foo, [...arguments]) / / 22 [1, 2]
arguments[0] = 99
console.log(foo, [...arguments]) / / 22, 99, 2)
}
fn(1.2)
Copy the code
arguments.callee
For non-strict mode, visit arguments.callee.
function fn() {
console.log(arguments.callee)
}
fn()
Copy the code
Strict mode, calls to arguments.callee are not supported.
'use strict'
function fn() {
console.log(arguments.callee) // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}
fn()
Copy the code
Why was arguments.callee removed from ES5 Strict mode?
There are two main reasons, the first being that browser engines are unlikely to implement inline and tail recursion based on the implementation arguments.callee.
Another reason is that when called recursively, this points to something different.
In the following recursive code, when the fn function is run, the internal this points to the window. But when I run arguments.callee, inside the function this points to arguments.
var args
function fn(val) {
if (val) {
console.log(this === args, this) // true Arguments []
} else {
console.log(this) // Window {}
args = arguments
arguments.callee(true)
}
}
fn()
Copy the code
The reason is simple: Arguments. callee refers to the current function, which is equivalent to adding a callee method to the arguments object. We know that this inside an object method generally refers to the caller, which is arguments here.
// arguments.callee = fn
arguments.callee(true)
Copy the code
this
Non-strict mode, normal function inside this refers to the top-level object.
function fn() {
console.log(this) // window {}
}
fn()
Copy the code
In strict mode, this points to undefined inside normal functions.
'use strict'
function fn() {
console.log(this) // undefined
}
fn()
Copy the code
Function.caller / Function.arguments
In non-strict mode, function. caller returns functions that call the current Function, and function. arguments return Function arguments.
function foo() {
function bar() {
console.log(bar.arguments) / / 3 4
console.log(bar.caller === foo) // true
}
bar(3.4)
}
foo()
Copy the code
Strict mode, disable function. caller and function.arguments.
'use strict'
function foo() {
function bar() {
console.log(bar.caller === foo) // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}
bar(3.4)
}
foo(1.2)
Copy the code
summary
- The function parameter name is unique
- Functional participation
arguments
Unbind - delete
arguments.callee
And disableFunction.caller
andFunction.arguments
- Inside ordinary functions
this
Point to theundefined
other
Simple data setting properties
Non-strict mode, simple data can be set attributes, but do not take effect.
var foo = 123
foo.true = 88
console.log(foo.true) // undefined
Copy the code
Strict mode, simple data setting property throws an error.
'use strict'
var foo = 123
foo.true = 88 // Uncaught TypeError: Cannot create property 'true' on number '123'
console.log(foo.true)
Copy the code
with
Non-strict mode, with is supported.
var foo = { bar: 1 }
with (foo) {
console.log(bar) / / 1
}
Copy the code
In strict mode, disable with.
'use strict'
var foo = { bar: 1 }
with (foo) { // Uncaught SyntaxError: Strict mode code may not include a with statement
console.log(bar)
}
Copy the code
eval
In non-strict mode, variables declared in EVAL are injected into the upper layer.
var x = 1
var z = eval('var y = 2; x + y')
console.log(x, z) / / 1 3
console.log(y) / / 2
Copy the code
In strict mode, variables declared in EVAL are only valid within the eval internal scope and are not injected into the upper layer.
'use strict'
var x = 1
var z = eval('var y = 2; x + y')
console.log(x, z) / / 1 3
console.log(y) // Uncaught ReferenceError: y is not defined
Copy the code
summary
- The simple data setting property throws an error
- disable
with
eval
Declare variables only ineval
The inner scope is valid and will not be injected into the upper layer
Q&A
Function declarations under block-level scopes
The results of the following code will vary significantly depending on the browser, supported version of ECMAScript, or level of implementation.
// 'use strict'
function fn() { console.log('outer')} (function () {
console.log(fn)
if (true) {
console.log(fn)
function fn() { console.log('inner') }
}
fn()
}())
Copy the code
In ES5 (IE10) in non-strict mode, fn will be promoted to the top of the function scope.
function fn() { console.log('outer')} (function () {
function fn() { console.log('inner')}console.log(fn) // function fn() { console.log('inner') }
if (true) {
console.log(fn) // function fn() { console.log('inner') }
}
fn() // inner} ())Copy the code
In IE10 strict mode, the parsing phase throws an error because ES5 explicitly declared functions under the if block are illegal.
'use strict'
function fn() { console.log('outer')} (function () {
console.log(fn)
if (true) {
console.log(fn)
function fn() { console.log('inner')}// In strict mode, function declarations cannot be nested within statements or blocks. These declarations only appear at the top level or directly in the function body.
}
fn()
}())
Copy the code
Non-strict mode in Chrome, Edge, IE11 and other ES6 browsers will be similar to var declarations and raised to the top of the block-level scope.
function fn() { console.log('outer')} (function () {
console.log(fn) // undefined
if (true) {
var fn = function () { console.log('inner')}console.log(fn) // function fn() { console.log('inner') }
}
fn() // inner} ())Copy the code
Chrome, Edge, IE11 and other ES6 browsers in strict mode will raise the top of the block-level scope.
'use strict'
function fn() { console.log('outer')} (function () {
console.log(fn) // fn() { console.log('outer') }
if (true) {
function fn() { console.log('inner')}console.log(fn) // fn() { console.log('inner') }
}
fn() // outer} ())Copy the code
So why?
Most browsers are now ES6, and IE10 supports ES5.
Let’s start with ES5, where it’s clear that function declarations in if blocks are illegal. In order to be compatible with older code, the browser does not fully comply with the specification and can run without error. But does the new code want to support this approach, so that the code can be regulated? So you can partially turn on strict mode.
In the case of ES6, block-level scopes are introduced, allowing functions to be declared under block-level scopes. Similarly, the browser does not strictly follow the ES6 specification for compatibility purposes, but it may differ from ES5. The strict pattern in ES6 clearly follows the specification.
The difference is that in ES5, there is no block-level scope, and functions in non-strict mode if blocks are promoted to the top of the function scope or global scope, and errors are thrown in the strict mode resolution phase. In ES6, block-level scope is introduced. In non-strict mode, functions in block-level scope are declared like VAR and raised to the top of the block-level scope. In strict mode, functions are raised to the top of the block-level scope.
It is also easy to see why.
In fact, a language can’t be perfect at first, and as time goes on, you’ll see JavaScript becoming more and more standardized, and there will be a lot of transition between strict mode and non-strict mode, which is used for browsers that are partially compliant with the specification and backwards compatible, Strict mode is used to strictly follow the specification.
It can be seen that JavaScript is currently in the transition stage to the standard language, and both modes are the products of this stage. In the future, if most of the web pages are running in strict mode, then one day in the future, the ‘use strict’ display declaration of strict mode will be abolished. Browsers will also default to strict mode.
🎉 is at the end
🍻 fellows, if you have seen this article and think it is helpful to you, please like 👍 or Star ✨ to support it!
Manual code word, if there is an error, welcome to the comment area correction 💬~
Your support is my biggest motivation to update 💪~
GitHub, Blog, nuggets, CSDN synchronous updates, welcome to pay attention to 😉~