JavaScript中void 0和undefined有什么区别

花开有时
花开有时
发布时间:2026-09-18| 3人浏览过
原创

在 JavaScript 中,void 0 与 undefined 的核心区别在于:undefined 是一个标识符(变量名),而 void 是一个一元运算符。void 0 通过执行求值并丢弃返回结果,恒定输出原始值 undefined;而标识符 undefined 在历史版本或局部作用域中存在被意外重写的风险。本文将深入拆解两者的本质差异、运行机制、代码体积考量及现代开发中的选择策略。

一、本质区别:标识符与一元运算符

很多开发者在阅读开源库源码(如早期的 Underscore、Lodash 或 Babel 编译产物)时,常会看到 void 0 代替直接写 undefined。理解这种写法的根本起点,是认清两者在语法层面的分类。

  • undefined 是标识符:它不是保留字,而是一个全局属性名,默认指向原始值 undefined。既然它是标识符,语法解析时就会将其当作普通变量对待。
  • void 是运算符:void <expression> 是一元表达式,负责对其后的表达式进行求值,然后无条件返回原始值 undefined。传入 0 只是因为它是最短且最轻量的求值表达式。
void 0 与 undefined 的语法构成对比
图 1:undefined 标识符寻址与 void 0 表达式运算的机制差异

二、核心差异一:可修改性与作用域遮蔽

造成 void 0 被广泛使用的首要原因,就是 undefined 可能会被修改或遮蔽。

1. 全局作用域(ECMAScript 3 历史遗留)

在 ECMAScript 3(例如较旧的 IE8 浏览器环境)中,全局对象上的 window.undefined 是可读可写的。只要执行 undefined = true,后续所有直接判断 value === undefined 的逻辑都会崩塌。

虽然从 ECMAScript 5 开始,全局的 undefined 已经被配置为不可写属性(writable: false),直接修改 window.undefined = "test" 会在非严格模式下静默失效或在严格模式下抛出 TypeError,但局部作用域依然存在隐患。

2. 局部作用域的变量遮蔽(Shadowing)

即使在现代浏览器和 Node.js 环境中,undefined 也并非语言保留字。在任何函数或代码块内部,开发者依然可以合法地声明一个名为 undefined 的局部变量:

function checkStatus(status) {
  // 在局部作用域中声明一个名为 undefined 的变量
  var undefined = "error";
  
  // 此处读取的是局部变量,而非原本的原始值
  console.log(status === undefined); 
}

checkStatus(undefined); 
// 输出结果为 false,因为 status 是真正的 undefined,而局部 undefined 变成了字符串 "error"

如果使用 void 0,无论当前作用域中是否遮蔽了变量,表达式都会由引擎内部计算并返回真正的空值,保证逻辑判断的确定性。

作用域遮蔽执行推导过程
图 2:局部作用域重写变量时的执行推导与结果分化

三、核心差异二:打包产物与字符开销

在前端工程化中,构建工具(如 Terser、esbuild、UglifyJS、SWC)非常偏爱 void 0。这主要是出于字符长度与压缩率的权衡:

  • undefined 占用 9 个字符。
  • void 0 只占用 6 个字符。

在没有 Gzip 之前,节省 3 个字符可以实打实减小代码体积。而在经过 Gzip 压缩后,虽然重复词汇的体积惩罚会显著降低,但通过编译器统一替换为 void 0 依然能建立更高的模式重复度,同时完全杜绝变量遮蔽对业务逻辑的破坏。

代码压缩与字符开销对比
图 3:代码压缩器中 void 0 对字符开销的优化

四、为什么是 void 0,而不是 void 1 或其他操作数?

void 运算符要求右侧必须跟一个表达式。在语法上,以下所有写法产生的结果完全等价:

void 0;           // undefined
void 1;           // undefined
void (true);      // undefined
void "hello";     // undefined
void (() => {});  // undefined

选择 0 仅仅因为它具有最短的字符长度(1 位)与最低的求值开销。数字字面量 0 在语法解析时无需任何复杂运算即可快速返回,因此 void 0 成为行业约定的标准范式。

注意事项:虽然 void 可以跟任何表达式,但必须注意运算符优先级与副作用。例如 void a = 1 会引发语法错误,正确写法应为 void (a = 1);此外,void doSomething() 会真实执行函数体,仅将其返回值替换为 undefined。

五、全维度对比:特性速查

为了更直观地区分两者,我们将语法特征、运行机制及工程行为汇总如下:

对比维度 undefined void 0
语法分类 标识符(全局变量属性) 一元表达式(操作符 + 字面量)
是否保留字 否(可作为局部变量名声明) 是(void 为语言内置关键字)
返回值可靠性 现代全局只读,但局部可能被遮蔽 100% 可靠,恒定返回原生 undefined
源码可读性 极佳,语义直观通用 一般,对初学者存在认知门槛
字符体积 9 字符 6 字符
主要出场场景 手写业务代码、参数默认值、类型注解 Babel/SWC 编译产物、压缩工具、老旧脚本

六、现代前端开发的实践建议

理解了原理后,很多开发者会疑惑:我们在当前日常写代码时,还需要刻意写 void 0 吗?

答案是:普通业务开发中建议直接使用 undefined,无需手动书写 void 0。

  1. 现代作用域规避了误伤:在开启严格模式("use strict")或基于 ES Module 组织的项目中,声明 var undefined = ... 属于极其不规范的操作,ESLint 默认规则(如 no-shadow-restricted-names)会直接报错拦截。
  2. 构建工具会自动处理:你在源码中保持 undefined 的高可读性,构建阶段 Vite、Webpack 等打包器的混淆插件(Terser、esbuild)会自动将满足条件的代码降级优化为 void 0。
  3. TypeScript 的普及:在 TypeScript 中,undefined 作为类型声明是必不可少的;滥用 void 0 替代空值判断反而会导致代码风格割裂。
全流程总结图
图 4:现代前端开发中兼顾可读性与生产安全的分层策略

总结来说,undefined 赢在可读性与语言语义,而 void 0 胜在纯粹的防御性与不可变性。了解这个差异,既能帮助你在阅读底层库与编译代码时消除困惑,也能更清晰地把握 JavaScript 作用域与表达式求值的本质逻辑。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。