WinddSnow

JavaScript-Strict-Mode

字数统计: 3.1k阅读时长: 12 min
2026/07/30

第55课:严格模式——"use strict" 限制、静默失败转异常、模块自动严格

严格模式(Strict Mode)是 ECMAScript 5 引入的一种受限的 JavaScript 执行变体。它刻意排除了语言中一些容易出错、不安全或设计不当的特性,使代码在更“干净”的环境下运行。在现代 JavaScript 开发中,严格模式几乎是默认开启的——ES Modules(import/export)和 class 定义自动处于严格模式。理解严格模式的具体限制、它如何将过去的“静默失败”转为显式异常,以及它对代码风格的约束,是写出安全、可维护、向前兼容的 JavaScript 代码的基础。


1. 严格模式的启用方式

1.1 脚本级启用

在脚本文件的最顶部(任何其他语句之前)添加 "use strict";'use strict';。它是一个字面量表达式语句,不被旧引擎视为命令,因此向后兼容。

1
2
3
4
5
<script>
"use strict";
// 整个脚本在严格模式下运行
const x = 10;
</script>

重要限制"use strict" 必须是脚本或函数体的第一条语句。如果前面有其他可执行语句(如 console.log),严格模式指令将失效,脚本仍以普通模式运行。

1
2
3
console.log('准备');
"use strict"; // 无效!前面已经有语句
// 以下代码仍在普通模式

1.2 函数级启用

可以在函数体的最顶部添加 "use strict";,使该函数及其嵌套函数在严格模式下运行。这种粒度允许逐步将遗留代码迁移到严格模式。

1
2
3
4
5
6
7
8
function strictFunction() {
"use strict";
// 此函数内部为严格模式
}

function normalFunction() {
// 此函数为普通模式
}

1.3 模块和类的自动严格模式

ES6 模块(.mjs 文件或 <script type="module">)以及使用 class 声明的所有代码,自动处于严格模式,无需显式添加 "use strict"

1
2
3
4
5
// 在一个 .mjs 文件中,或 <script type="module"> 中
// 以下代码自动严格
export function test() {
console.log(this); // undefined(严格模式下全局函数 this 为 undefined)
}
1
2
3
4
5
class MyClass {
method() {
// 类内部自动严格
}
}

在现代项目中,由于绝大多数代码通过 ES Modules 组织,**通常不需要手动写 "use strict"**。


2. 静默失败转为显式错误

在普通模式下,许多误操作会静默失败(什么也不发生,也不报错)。严格模式将这些行为改为抛出异常,使错误尽早暴露。

2.1 对不可写属性赋值

1
2
3
4
5
6
7
8
"use strict";

const obj = {};
Object.defineProperty(obj, 'readOnly', { value: 42, writable: false });

// 普通模式:静默失败,obj.readOnly 仍为 42
// 严格模式:抛出 TypeError
obj.readOnly = 100; // TypeError: Cannot assign to read only property 'readOnly'

2.2 对不可扩展对象添加属性

1
2
3
4
5
6
7
8
"use strict";

const obj = { a: 1 };
Object.preventExtensions(obj);

// 普通模式:静默失败
// 严格模式:抛出 TypeError
obj.b = 2; // TypeError: Cannot add property b, object is not extensible

2.3 删除不可删除的属性

1
2
3
4
5
"use strict";

// 普通模式:delete 不可删除属性返回 false,无错误
// 严格模式:抛出 TypeError
delete Object.prototype; // TypeError: Cannot delete property 'prototype' of function Object()

2.4 函数参数重名

1
2
3
4
5
6
7
"use strict";

// 普通模式:后面的参数覆盖前面的,不报错
// 严格模式:SyntaxError
function sum(a, a) { // SyntaxError: Duplicate parameter name not allowed
return a + a;
}

2.5 八进制字面量

1
2
3
4
5
"use strict";

// 普通模式:0123 被视为八进制(值为 83)
// 严格模式:SyntaxError
const num = 0123; // SyntaxError: Octal literals are not allowed in strict mode

注意:ES6 引入了合法的八进制语法 0o123(以 0o 开头),在严格模式和普通模式下均可用。

2.6 对 evalarguments 的赋值

1
2
3
4
5
6
"use strict";

// 普通模式:eval 可以被当作变量名赋值
// 严格模式:SyntaxError
let eval = 5; // SyntaxError
let arguments = []; // SyntaxError

3. 变量使用的安全性增强

3.1 禁止意外创建全局变量

在普通模式下,对未声明的变量赋值会隐式创建全局变量。严格模式禁止这一行为,抛出 ReferenceError

1
2
3
4
5
"use strict";

// 普通模式:隐式创建全局变量 myVar
// 严格模式:ReferenceError
myVar = 10; // ReferenceError: myVar is not defined

这是严格模式最重要的安全性提升之一——防止因拼写错误导致的全局变量污染。

3.2 禁止使用 with 语句

with 语句将对象属性推入作用域链的前端,使代码的含义在编译时无法确定(难以优化且易出错)。严格模式禁止使用 with

1
2
3
4
5
6
"use strict";

const obj = { a: 1 };
with (obj) { // SyntaxError: Strict mode code may not include a with statement
console.log(a);
}

3.3 eval 不再在包含作用域中引入变量

在严格模式下,eval 创建的变量和函数仅存在于 eval 内部的独立作用域中,不会“泄漏”到外层。

1
2
3
4
5
6
"use strict";

eval("var x = 10;");
console.log(x); // ReferenceError: x is not defined

// 普通模式下,x 会被创建在外层作用域

3.4 delete 只能用于对象属性

在普通模式下,delete 用于变量名会静默失败。严格模式下抛出 SyntaxError

1
2
3
4
"use strict";

let x = 10;
delete x; // SyntaxError: Delete of an unqualified identifier in strict mode

4. this 绑定行为的变化

严格模式下,函数的 this 值不再被自动包装为对象,且在无明确调用者时保持 undefined(或原始值),而非默认指向全局对象。

4.1 全局函数中的 this

1
2
3
4
5
6
7
8
9
"use strict";

function showThis() {
console.log(this);
}

// 普通模式:this 指向全局对象(window 或 global)
// 严格模式:this 为 undefined
showThis(); // undefined

4.2 方法调用中的 this

严格模式下,方法调用的 this 仍指向调用该方法的对象(与普通模式一致)。

1
2
3
4
5
6
7
8
"use strict";

const user = {
name: 'Alice',
greet() { console.log(this.name); }
};

user.greet(); // 'Alice' —— this 指向 user,与普通模式相同

4.3 call / apply / bind 传入的原始值不被包装

1
2
3
4
5
6
7
8
"use strict";

function showThis() { console.log(this); }

// 普通模式:传入的原始值被包装为对象(Number、String 等)
// 严格模式:原始值保持原样
showThis.call(42); // 42(不是 Number 对象)
showThis.call(null); // null(不是全局对象)

5. arguments 对象的变化

5.1 arguments 不再与形参动态绑定

在普通模式下,arguments 的元素与对应形参共享引用(修改形参会影响 arguments 对应项,反之亦然)。严格模式下,两者是独立的副本

1
2
3
4
5
6
7
"use strict";

function demo(x) {
x = 20;
console.log(arguments[0]); // 10 —— 形参修改不影响 arguments
}
demo(10);

普通模式下,上述代码输出 20,因为 xarguments[0] 是同一个引用。

5.2 arguments.callee 被禁止

arguments.callee 指向当前函数自身,常用于匿名函数递归。严格模式下访问它会抛出 TypeError

1
2
3
4
5
6
"use strict";

function factorial(n) {
// 严格模式下抛出 TypeError
// console.log(arguments.callee);
}

替代方案:使用具名函数表达式或直接使用函数名进行递归。


6. 严格模式与模块化的关系

在现代 JavaScript 项目中,你几乎不需要显式书写 "use strict"。原因如下:

场景 是否自动严格
ES Modules(import/export ✅ 自动严格
class 内部 ✅ 自动严格
<script type="module"> ✅ 自动严格
普通 <script> 脚本 ❌ 需手动添加
函数内部("use strict" 包裹) ❌ 需手动添加

在大多数现代框架(React、Vue、Angular)生成的项目中,所有代码通过 ESM 组织,因此严格模式已默认覆盖。


课后练习

一、概念自测(选择题 / 填空题)

  1. (单选) 在严格模式下,对未声明的变量赋值会发生什么?
    A. 静默失败,不产生任何效果。
    B. 隐式创建全局变量。
    C. 抛出 ReferenceError
    D. 抛出 SyntaxError

  2. (单选) 在严格模式下,全局函数直接调用时 this 的值是?
    A. 全局对象 window
    B. null
    C. undefined
    D. 调用该函数的对象

  3. (填空) 要在整个脚本文件顶部启用严格模式,应在所有语句之前添加 ______

  4. (多选) 以下哪些场景会自动启用严格模式(无需手动添加 "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" 包裹。

课后练习答案

一、概念自测答案

  1. C

    • 解析:严格模式下,对未声明变量赋值会抛出 ReferenceError,避免意外全局变量污染。
  2. C

    • 解析:严格模式下全局函数直接调用时 thisundefined,而非全局对象。
  3. "use strict"

    • 解析:"use strict"(或 'use strict')是启用严格模式的指令,必须置于作用域顶部。
  4. A、B、D

    • 解析:ES Modules、class 内部、<script type="module"> 均自动启用严格模式。普通 <script> 标签不会自动严格。

二、AI 编程任务参考答案(提示词示例)

示例提示词
“请编写一个 JavaScript 函数 mergeConfigs(defaults, overrides),在严格模式下合并两个配置对象。要求:

  • 文件第一行写 'use strict';
  • 使用 const 声明函数,添加 JSDoc 注释。
  • 参数校验:如果任一参数 typeof 不是 'object' 或为 null,抛出 TypeError 并包含清晰的错误消息。
  • 使用 Object.assign({}, defaults, overrides) 合并。
  • 对返回对象调用 Object.freeze 使其不可变。
  • 提供使用示例注释:传入两个配置对象,验证合并和冻结效果。
  • 直接输出完整代码。”
CATALOG
  1. 1. 第55课:严格模式——"use strict" 限制、静默失败转异常、模块自动严格
    1. 1.1. 1. 严格模式的启用方式
      1. 1.1.1. 1.1 脚本级启用
      2. 1.1.2. 1.2 函数级启用
      3. 1.1.3. 1.3 模块和类的自动严格模式
    2. 1.2. 2. 静默失败转为显式错误
      1. 1.2.1. 2.1 对不可写属性赋值
      2. 1.2.2. 2.2 对不可扩展对象添加属性
      3. 1.2.3. 2.3 删除不可删除的属性
      4. 1.2.4. 2.4 函数参数重名
      5. 1.2.5. 2.5 八进制字面量
      6. 1.2.6. 2.6 对 eval 和 arguments 的赋值
    3. 1.3. 3. 变量使用的安全性增强
      1. 1.3.1. 3.1 禁止意外创建全局变量
      2. 1.3.2. 3.2 禁止使用 with 语句
      3. 1.3.3. 3.3 eval 不再在包含作用域中引入变量
      4. 1.3.4. 3.4 delete 只能用于对象属性
    4. 1.4. 4. this 绑定行为的变化
      1. 1.4.1. 4.1 全局函数中的 this
      2. 1.4.2. 4.2 方法调用中的 this
      3. 1.4.3. 4.3 call / apply / bind 传入的原始值不被包装
    5. 1.5. 5. arguments 对象的变化
      1. 1.5.1. 5.1 arguments 不再与形参动态绑定
      2. 1.5.2. 5.2 arguments.callee 被禁止
    6. 1.6. 6. 严格模式与模块化的关系
    7. 1.7. 课后练习
      1. 1.7.1. 一、概念自测(选择题 / 填空题)
      2. 1.7.2. 二、AI 编程任务:编写面向 AI 的提示词
      3. 1.7.3. 三、面试真题与参考答案
    8. 1.8. 课后练习答案
      1. 1.8.1. 一、概念自测答案
      2. 1.8.2. 二、AI 编程任务参考答案(提示词示例)