严格模式(Strict Mode)全面解析
严格模式是 ES5 引入的一种限制性执行模式,通过消除 JavaScript 语言的一些不合理、不严谨之处,减少语法陷阱,提高代码安全性和运行效率;
启用严格模式
-
严格模式可作用于全局或函数局部 (推荐局部,避免污染全局);
-
注意:‘use strict’ 必须是代码块的第一个语句 (前面不能有除注释外的任何代码),否则失效;
// 1. 全局严格模式(不推荐,会影响所有代码)
'use strict';
// 2. 函数局部严格模式(推荐,仅作用于当前函数)
function fn() {
'use strict';
// 严格模式下的代码
}
// 3. ES6 模块/类默认启用严格模式(无需手动声明)
export const a = 1; // 模块内自动严格模式
class Test {} // 类内自动严格模式
严格模式的核心规则(重点)
| 常规模式行为 | 严格模式行为 | 目的 |
|---|---|---|
| 未声明变量赋值自动创建全局变量 | 直接抛出 ReferenceError | 杜绝意外全局变量 |
| this 在全局函数中指向 window | 全局函数中 this 为 undefined | 避免误操作全局对象 |
| 函数参数名可重复 (后定义覆盖前) | 参数名重复抛出 SyntaxError | 避免参数名冲突 |
| delete 不可配置属性不报错 (静默失败) | 抛出 TypeError | 明确删除操作的合法性 |
| 允许八进制字面量 (如 0123) | 禁止八进制字面量 (需用 0o123) | 统一数值语法 |
| with 语句可用 | 禁止使用 with 语句 | 避免作用域混乱,提升性能 |
| 变量 / 函数可重写 eval/arguments | 禁止重写 eval/arguments | 保护核心对象 |
| arguments 与实参联动 (修改实参同步修改 arguments) | arguments 是实参的静态副本 | 避免隐式联动问题 |
| 允许 eval 注入变量到当前作用域 | eval 有独立作用域 (仅内部可访问) | 减少作用域污染 |
| 禁止为只读属性赋值 (静默失败) | 抛出 TypeError | 明确赋值错误 |
| caller/callee 属性可用 | 访问 arguments.callee/caller 抛出 TypeError | 禁止递归依赖,优化性能 |
关键规则示例
-
禁止未声明变量赋值
// 常规模式:自动创建全局变量 a = 10; // 全局变量 a = 10 // 严格模式:抛出 ReferenceError 'use strict'; b = 20; // Uncaught ReferenceError: b is not defined -
this 指向变化
// 常规模式:全局函数 this → window function fn1() { console.log(this); // window } fn1(); // 严格模式:全局函数 this → undefined 'use strict'; function fn2() { console.log(this); // undefined } fn2(); // 构造函数忘记 new:常规模式 this → window,严格模式抛错 function Person() { 'use strict'; this.name = '张三'; // 未 new 调用时:Uncaught TypeError: Cannot set property 'name' of undefined } Person(); // 报错(需 new Person()) -
参数名不可重复
// 常规模式:参数名重复,后一个覆盖前一个 function fn(a, a) { console.log(a); // 2 } fn(1, 2); // 严格模式:抛出 SyntaxError 'use strict'; function fn(a, a) {} // Uncaught SyntaxError: Duplicate parameter name not allowed in this context -
arguments 静态化
// 常规模式:arguments 与实参联动 function fn(a) { a = 2; console.log(arguments[0]); // 2 } fn(1); // 严格模式:arguments 是静态副本,不联动 'use strict'; function fn(a) { a = 2; console.log(arguments[0]); // 1 } fn(1); -
禁止删除不可配置属性
// 常规模式:静默失败 delete Object.prototype; // false(无报错) // 严格模式:抛出 TypeError 'use strict'; delete Object.prototype; // Uncaught TypeError: Cannot delete property 'prototype' of function Object() { [native code] }
经典面试题
以下代码在严格模式下输出什么?为什么?
'use strict';
var obj = {
name: '李四',
sayName: function() {
console.log(this.name);
}
};
var fn = obj.sayName;
fn();
1. 抛出 Uncaught TypeError: Cannot read property 'name' of undefined
2. 解析:
严格模式下,全局执行的函数 this 指向 undefined(而非 window);
fn 是独立调用(而非 obj.sayName()),this 绑定丢失,指向 undefined;
访问 undefined.name 触发类型错误;
严格模式下,arguments.callee 为什么不能用?如何替代?
// 常规模式:递归可用 arguments.callee
function factorial(n) {
if (n === 1) return 1;
return n * arguments.callee(n - 1);
}
console.log(factorial(5)); // 120
// 严格模式:以下代码报错,如何修复?
'use strict';
function factorial(n) {
if (n === 1) return 1;
return n * arguments.callee(n - 1);
}
'use strict';
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1); // 直接用函数名
}
console.log(factorial(5)); // 120
// 报错原因:严格模式禁止访问 arguments.callee(会抛出 TypeError),目的是避免递归依赖、提升代码可维护性;
// 替代方案:使用函数名递归(或命名函数表达式):
以下代码在严格模式下是否报错?说明原因
'use strict';
eval('var x = 10;');
console.log(x);
1. 答案:抛出 ReferenceError: x is not defined
2. 解析:
常规模式下,eval 内声明的变量会注入到当前作用域;
严格模式下,eval 有独立的作用域,内部变量仅在 eval 内有效,外部无法访问;
严格模式下,以下代码执行结果是什么?
'use strict';
function test(a, b) {
a = 10;
b = 20;
console.log(arguments[0], arguments[1]);
}
test(1, 2);
1. 答案:输出 1 2
2. 解析:严格模式下
arguments 是实参的静态副本,修改形参不会同步到 arguments;
常规模式下会输出 10 20;
严格模式下,为什么禁止使用 with 语句?
-
答案:
- with 语句会创建临时作用域,导致 JS 引擎无法优化代码 (作用域查找变慢),降低性能;
- with 容易导致变量名冲突 (如 with(obj) { a = 1; } 无法确定 a 是全局变量还是 obj 的属性);
- 严格模式禁用 with,强制开发者使用更清晰的写法 (如 obj.a = 1),提升代码可读性和性能;
-
with 语句的工作原理 (作用域链扩展):
- JS 执行代码时,会通过作用域链查找变量 / 属性:
- 正常情况下,作用域链顺序:当前执行上下文的变量对象 → 外层函数变量对象 → 全局变量对象;
- 进入 with 代码块时,引擎会创建一个临时变量对象 (包含传入对象的所有属性),并将其插入到作用域链的最顶端;
- 代码块内查找属性时,优先查这个临时对象,找不到再按原作用域链查找;
- 退出 with 代码块后,临时变量对象被移除,作用域链恢复原样;
正则表达式👉 JavaScript 中的应用
上一篇