第55课:严格模式——"use strict" 限制、静默失败转异常、模块自动严格
严格模式(Strict Mode)是 ECMAScript 5 引入的一种受限的 JavaScript 执行变体。它刻意排除了语言中一些容易出错、不安全或设计不当的特性,使代码在更“干净”的环境下运行。在现代 JavaScript 开发中,严格模式几乎是默认开启的——ES Modules(import/export)和 class 定义自动处于严格模式。理解严格模式的具体限制、它如何将过去的“静默失败”转为显式异常,以及它对代码风格的约束,是写出安全、可维护、向前兼容的 JavaScript 代码的基础。
1. 严格模式的启用方式
1.1 脚本级启用
在脚本文件的最顶部(任何其他语句之前)添加 "use strict"; 或 'use strict';。它是一个字面量表达式语句,不被旧引擎视为命令,因此向后兼容。
1 | <script> |
重要限制:"use strict" 必须是脚本或函数体的第一条语句。如果前面有其他可执行语句(如 console.log),严格模式指令将失效,脚本仍以普通模式运行。
1 | console.log('准备'); |
1.2 函数级启用
可以在函数体的最顶部添加 "use strict";,使该函数及其嵌套函数在严格模式下运行。这种粒度允许逐步将遗留代码迁移到严格模式。
1 | function strictFunction() { |
1.3 模块和类的自动严格模式
ES6 模块(.mjs 文件或 <script type="module">)以及使用 class 声明的所有代码,自动处于严格模式,无需显式添加 "use strict"。
1 | // 在一个 .mjs 文件中,或 <script type="module"> 中 |
1 | class MyClass { |
在现代项目中,由于绝大多数代码通过 ES Modules 组织,**通常不需要手动写 "use strict"**。
2. 静默失败转为显式错误
在普通模式下,许多误操作会静默失败(什么也不发生,也不报错)。严格模式将这些行为改为抛出异常,使错误尽早暴露。
2.1 对不可写属性赋值
1 | ; |
2.2 对不可扩展对象添加属性
1 | ; |
2.3 删除不可删除的属性
1 | ; |
2.4 函数参数重名
1 | ; |
2.5 八进制字面量
1 | ; |
注意:ES6 引入了合法的八进制语法 0o123(以 0o 开头),在严格模式和普通模式下均可用。
2.6 对 eval 和 arguments 的赋值
1 | ; |
3. 变量使用的安全性增强
3.1 禁止意外创建全局变量
在普通模式下,对未声明的变量赋值会隐式创建全局变量。严格模式禁止这一行为,抛出 ReferenceError。
1 | ; |
这是严格模式最重要的安全性提升之一——防止因拼写错误导致的全局变量污染。
3.2 禁止使用 with 语句
with 语句将对象属性推入作用域链的前端,使代码的含义在编译时无法确定(难以优化且易出错)。严格模式禁止使用 with。
1 | ; |
3.3 eval 不再在包含作用域中引入变量
在严格模式下,eval 创建的变量和函数仅存在于 eval 内部的独立作用域中,不会“泄漏”到外层。
1 | ; |
3.4 delete 只能用于对象属性
在普通模式下,delete 用于变量名会静默失败。严格模式下抛出 SyntaxError。
1 | ; |
4. this 绑定行为的变化
严格模式下,函数的 this 值不再被自动包装为对象,且在无明确调用者时保持 undefined(或原始值),而非默认指向全局对象。
4.1 全局函数中的 this
1 | ; |
4.2 方法调用中的 this
严格模式下,方法调用的 this 仍指向调用该方法的对象(与普通模式一致)。
1 | ; |
4.3 call / apply / bind 传入的原始值不被包装
1 | ; |
5. arguments 对象的变化
5.1 arguments 不再与形参动态绑定
在普通模式下,arguments 的元素与对应形参共享引用(修改形参会影响 arguments 对应项,反之亦然)。严格模式下,两者是独立的副本。
1 | ; |
普通模式下,上述代码输出 20,因为 x 和 arguments[0] 是同一个引用。
5.2 arguments.callee 被禁止
arguments.callee 指向当前函数自身,常用于匿名函数递归。严格模式下访问它会抛出 TypeError。
1 | ; |
替代方案:使用具名函数表达式或直接使用函数名进行递归。
6. 严格模式与模块化的关系
在现代 JavaScript 项目中,你几乎不需要显式书写 "use strict"。原因如下:
| 场景 | 是否自动严格 |
|---|---|
ES Modules(import/export) |
✅ 自动严格 |
class 内部 |
✅ 自动严格 |
<script type="module"> |
✅ 自动严格 |
普通 <script> 脚本 |
❌ 需手动添加 |
函数内部("use strict" 包裹) |
❌ 需手动添加 |
在大多数现代框架(React、Vue、Angular)生成的项目中,所有代码通过 ESM 组织,因此严格模式已默认覆盖。
课后练习
一、概念自测(选择题 / 填空题)
(单选) 在严格模式下,对未声明的变量赋值会发生什么?
A. 静默失败,不产生任何效果。
B. 隐式创建全局变量。
C. 抛出ReferenceError。
D. 抛出SyntaxError。(单选) 在严格模式下,全局函数直接调用时
this的值是?
A. 全局对象window
B.null
C.undefined
D. 调用该函数的对象(填空) 要在整个脚本文件顶部启用严格模式,应在所有语句之前添加
______。(多选) 以下哪些场景会自动启用严格模式(无需手动添加
"use strict")?
A. ES Modules(import/export)
B.class内部
C. 普通<script>标签
D.<script type="module">
二、AI 编程任务:编写面向 AI 的提示词
场景:你需要编写一个 JavaScript 函数 mergeConfigs(defaults, overrides),它接收两个配置对象,合并后返回一个新对象。要求如下:
- 在严格模式下运行(显式添加
"use strict")。 - 如果任一参数不是普通对象(
typeof不是'object'或为null),抛出TypeError,并附带清晰的错误消息。 - 使用
Object.assign({}, defaults, overrides)进行合并(overrides的相同属性覆盖defaults)。 - 使用
Object.freeze冻结返回的对象,使调用方无法修改合并后的配置。 - 添加 JSDoc 注释说明参数、返回值和可能抛出的错误。
任务要求:请写出一段完整的中文提示词,发送给 AI,使其生成符合上述要求的 JavaScript 函数。提示词中需明确指定严格模式的启用方式、参数校验逻辑、合并与冻结操作。
三、面试真题与参考答案
题目(滴滴前端面试题):
请详细说明 JavaScript 严格模式(Strict Mode)与普通模式的主要区别,至少列出 5 项。为什么现代 JavaScript 开发中几乎不需要手动写
"use strict"?
参考答案:
1. 主要区别(列出 5 项):
| 行为 | 普通模式 | 严格模式 |
|---|---|---|
| 未声明变量赋值 | 隐式创建全局变量。 | 抛出 ReferenceError。 |
全局函数中的 this |
指向全局对象(window)。 |
为 undefined。 |
| 函数参数重名 | 静默允许,后者覆盖前者。 | 抛出 SyntaxError。 |
with 语句 |
允许使用。 | 禁止使用,抛出 SyntaxError。 |
eval 引入变量 |
变量泄漏到外层作用域。 | 变量仅存在于 eval 内部作用域。 |
| 对不可写属性赋值 | 静默失败。 | 抛出 TypeError。 |
八进制字面量 0123 |
允许(视为八进制)。 | 禁止,抛出 SyntaxError。 |
arguments 与形参绑定 |
共享引用,修改形参影响 arguments。 |
独立副本,互不影响。 |
delete 删除变量 |
静默失败。 | 抛出 SyntaxError。 |
2. 现代开发中无需手动写的原因:
- ES Modules(
.mjs文件、<script type="module">)自动启用严格模式,而现代项目几乎全部使用 ESM 组织代码。 class声明内部自动处于严格模式,使用class的代码不需要手动声明。- 主流框架(React、Vue、Angular)和构建工具(Vite、Webpack)默认将代码视为模块处理,严格模式已覆盖。
3. 仍需手动添加的场景:
- 直接通过
<script>标签引入的传统脚本(不设type="module"),且需要严格模式约束时。 - 在函数内部逐步迁移遗留代码,使用函数级
"use strict"包裹。
课后练习答案
一、概念自测答案
C
- 解析:严格模式下,对未声明变量赋值会抛出
ReferenceError,避免意外全局变量污染。
- 解析:严格模式下,对未声明变量赋值会抛出
C
- 解析:严格模式下全局函数直接调用时
this为undefined,而非全局对象。
- 解析:严格模式下全局函数直接调用时
"use strict"- 解析:
"use strict"(或'use strict')是启用严格模式的指令,必须置于作用域顶部。
- 解析:
A、B、D
- 解析:ES Modules、
class内部、<script type="module">均自动启用严格模式。普通<script>标签不会自动严格。
- 解析:ES Modules、
二、AI 编程任务参考答案(提示词示例)
示例提示词:
“请编写一个 JavaScript 函数mergeConfigs(defaults, overrides),在严格模式下合并两个配置对象。要求:
- 文件第一行写
'use strict';。- 使用
const声明函数,添加 JSDoc 注释。- 参数校验:如果任一参数
typeof不是'object'或为null,抛出TypeError并包含清晰的错误消息。- 使用
Object.assign({}, defaults, overrides)合并。- 对返回对象调用
Object.freeze使其不可变。- 提供使用示例注释:传入两个配置对象,验证合并和冻结效果。
- 直接输出完整代码。”