前言
Hello~大家好。我是秋天的一阵风
对于很多初中级前端开发人员来说,严格模式 可能是一个相对陌生的概念。在当前的开发环境中,各种响应式框架层出不穷,如Vue、React、Angular
等,这些框架极大地提高了开发效率,让开发者能够快速构建出功能强大的前端应用。然而,在这种快速开发的浪潮中,一些基础但重要的概念,比如严格模式,往往被开发者们忽略。
本文将从严格模式的基本概念出发,深入探讨严格模式在代码中的差异性。希望通过本文的介绍,能够帮助初中级前端开发者更好地理解严格模式,从而在日常开发中写出更规范、更可靠的代码。
一、什么是严格模式?
JavaScript严格模式是一种特殊的运行模式,它通过限制一些不规范的语法和行为,帮助开发者避免潜在的错误,提高代码的可维护性和稳定性。严格模式的主要好处包括:
-
防止意外全局变量的声明:在非严格模式下,未声明的变量可能会被自动提升为全局变量,这可能导致全局作用域的污染和难以追踪的错误。严格模式禁止了这种行为,确保所有变量都必须先声明再使用,从而避免了意外的全局变量声明。
-
增强代码的规范性 :严格模式禁止了一些不规范的语法和行为,如对
undefined
、Infinity
等特殊值的赋值,以及使用with
语句等。这些限制有助于开发者编写更规范、更清晰的代码,减少潜在的错误和问题。 -
提高代码的调试效率:严格模式会在一些可能导致错误的操作上抛出异常,而不是默默地忽略这些问题。这使得开发者能够在开发过程中更早地发现和修复错误,提高调试效率。
-
为未来的 ECMAScript 版本铺平道路 :未来版本的
ECMAScrip
t 很有可能会引入新语法,ECMAScript5
中的严格模式就提早设置了一些限制来减轻之后版本改变产生的影响。如果提早使用了严格模式中的保护机制,那么做出改变就会变得更容易。
二、如何开启严格模式?
显示开启严格模式
1. 为脚本开启严格模式
将
'use strict'
放在所有语句之前
js
// 整个脚本都开启严格模式的语法
"use strict";
const msg = "整个脚本都开启严格模式";
2. 为函数开启严格模式
将
'use strict'
放在函数体所有语句之前
js
function myStrictFunction() {
// 函数级别严格模式语法
"use strict";
function nested() {
return "我也一样!";
}
return `你好!我是严格模式的函数!${nested()}`;
}
function myNotStrictFunction() {
return "我不是严格模式的函数。";
}
隐式开启严格模式
在JavaScript中,除了显式地使用'use strict';
声明来开启严格模式外,还有一些隐式的情况会自动启用严格模式。这些隐式严格模式主要出现在某些特定的上下文中,确保代码的执行符合严格模式的规则。
1. 模块环境(ES6模块)
在ES6模块中,所有代码默认运行在严格模式下。这意味着,如果你在使用import
和export
语法的模块中编写代码,这些代码会自动运行在严格模式下,而无需显式地添加'use strict';
声明。
js
// ES6模块
export function add(a, b) {
return a + b;
}
2. 类的构造函数和方法
在ES6中,类的构造函数和方法也默认运行在严格模式下。这意味着,当你使用class
语法定义类时,类中的所有方法和构造函数都会自动启用严格模式。
js
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
3. 箭头函数
箭头函数在ES6中引入,它们默认运行在严格模式下。这意味着,当你使用箭头函数时,这些函数会自动启用严格模式,而无需显式地添加'use strict';
声明。
js
const add = (a, b) => {
return a + b;
};
三、严格模式下的代码差异有哪些?
1. 变量操作的差异性
非严格模式
- 使用前无需用
var
声明变量,未声明的变量会被自动提升为全局变量。 - 可以直接对对象操作
delete
。 - 在正常模式下
delete
一个被var
的变量,会失败(静默失败)且不会报错。
JavaScript
// 非严格模式
a = 1; // 未声明直接赋值,a成为全局变量
console.log(Object.getOwnPropertyDescriptor(window, 'a'));
// {value: 1, writable: true, enumerable: true, configurable: true}
var a = 1;
console.log(Object.getOwnPropertyDescriptor(window, 'a'));
// {value: 1, writable: true, enumerable: true, configurable: false}
delete window.a; // 不报错,但delete失败
console.log(a); // 1
严格模式
- 使用前必须用
var
声明变量,否则会抛出ReferenceError
错误。 - 不能直接对对象操作
delete
,会抛出TypeError
错误。 - 在严格模式下
delete
一个被var
的变量,会变成报错。
JavaScript
// 严格模式
'use strict';
var a = 1;
delete window.a; // 报错:Uncaught TypeError: Cannot delete property 'a' of [object Window]
2. 函数的this指向undefined
非严格模式
函数的this
指向全局对象(在浏览器中是window
)。
JavaScript
// 非严格模式
function test() {
console.log(this === window); // true
}
test();
严格模式
函数的this
指向undefined
。
JavaScript
// 严格模式
'use strict';
function test() {
console.log(this === undefined); // true
}
test();
3. 禁止使用八进制
非严格模式
允许使用八进制表示。
JavaScript
// 非严格模式
var value = 01010; // 八进制
console.log(value); // 520
严格模式
不允许使用八进制表示,会抛出SyntaxError
错误。
JavaScript
// 严格模式
'use strict';
var value = 01010; // 报错:Uncaught SyntaxError: Octal literals are not allowed in strict mode.
4. eval
和arguments
不能作为标识符
非严格模式
可以使用eval
和arguments
作为标识符。
JavaScript
// 非严格模式
var eval = 1;
var arguments = 2;
console.log(eval); // 1
console.log(arguments); // 2
严格模式
使用eval
和arguments
作为标识符会抛出SyntaxError
错误。
JavaScript
// 严格模式
'use strict';
var eval = 1; // 报错:Uncaught SyntaxError: Unexpected eval or arguments in strict mode
var arguments = 2; // 报错:Uncaught SyntaxError: Unexpected eval or arguments in strict mode
5. 不能使用with()
非严格模式
可以使用with()
。
JavaScript
// 非严格模式
var obj = { a: 1 };
with (obj) {
console.log(a); // 1
}
严格模式
使用with()
会抛出SyntaxError
错误。
JavaScript
// 严格模式
'use strict';
var obj = { a: 1 };
with (obj) { // 报错:Uncaught SyntaxError: Strict mode code may not include a with statement
console.log(a);
}
6. 不能使用arguments.callee
和caller
非严格模式
可以使用arguments.callee
和caller
。
JavaScript
// 非严格模式
function test() {
console.log(arguments.callee === test); // true
}
test();
function outer() {
inner();
}
function inner() {
console.log(inner.caller === outer); // true
}
outer();
严格模式
使用arguments.callee
和caller
会抛出TypeError
错误。
JavaScript
// 严格模式
'use strict';
function test() {
console.log(arguments.callee === test); // 报错:Uncaught TypeError: 'callee' and 'caller' are restricted function properties and cannot be accessed in this context
}
test();
function outer() {
inner();
}
function inner() {
console.log(inner.caller === outer); // 报错:Uncaught TypeError: 'callee' and 'caller' are restricted function properties and cannot be accessed in this context
}
outer();
7. 实参和形参没有映射关系
非严格模式
通过arguments[0]
修改实参,形参也会变化。
JavaScript
// 非严格模式
function test(a) {
arguments[0] = 20;
console.log(a); // 20
}
test(10);
严格模式
修改arguments[0]
不会影响形参。
JavaScript
// 严格模式
'use strict';
function test(a) {
arguments[0] = 20;
console.log(a); // 10
}
test(10);
8. 参数是唯一的
非严格模式
函数参数可以是多个相同值且后面的会覆盖前面的值。
JavaScript
// 非严格模式
function test(a, a) {
console.log(a); // 20
}
test(10, 20);
严格模式
函数参数必须是唯一的,否则会抛出SyntaxError
错误。
JavaScript
// 严格模式
'use strict';
function test(a, a) { // 报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context
console.log(a);
}
test(10, 20);
9. 对象操作的差异性
非严格模式
- 对象可以有重名属性,后面的会覆盖前面的值。
- 属性描述符出现不当操作的时候,会静默失败,不会报错。
JavaScript
// 非严格模式
var obj = {
name: 'owllai',
name: 'owl'
};
console.log(obj); // { name: 'owl' }
Object.defineProperty(obj, 'name', {
configurable: false
});
delete obj.name; // 不报错,但delete失败
console.log(obj); // { name: 'owl' }
严格模式
- 对象不能有重名属性,否则会抛出
SyntaxError
错误。 - 属性描述符出现不当操作的时候,会直接报错。
JavaScript
// 严格模式
'use strict';
var obj = {
name: 'owllai',
name: 'owl' // 报错:Uncaught SyntaxError: Duplicate data property in object literal not allowed in strict mode
};
Object.defineProperty(obj, 'name', {
configurable: false
});
delete obj.name; // 报错:Uncaught TypeError: Cannot delete property 'name' of #<Object>