JavaScript检测死代码需结合工具与人工:ESLint通过AST/CFG识别不可达语句,TypeScript在strict模式下增强控制流分析,Webpack/Rollup通过Tree Shaking验证残留逻辑,而IIFE、模块副作用和动态注册等需人工排查。

JavaScript 中检测无法达到的死代码,核心是让工具能“看清控制流路径”并“确认某段代码永远走不到”。现代静态分析工具不是靠猜,而是基于抽象语法树(AST)和控制流图(CFG)做推断。关键在于选对工具、配好规则、理解它的能力边界。
用 ESLint 精准捕获常见不可达语句
ESLint 内置的 Unreachable statement 规则能直接识别 return/throw/break 后面的代码,比如:
-
function foo() { return; console.log('dead'); }→ 第二行被高亮为不可达 -
if (false) { doSomething(); }→ 整个块默认被标记(需启用no-unreachable) -
while (false) {...}或恒假条件分支,也会触发警告
注意:它对动态条件(如 if (process.env.NODE_ENV === 'dev'))通常不报错,除非你配置了环境变量预定义或使用 eslint-plugin-import 的常量折叠插件。
借助 TypeScript 提升控制流分析精度
TypeScript 编译器在 strict 模式下会主动分析控制流中的类型收敛与不可达分支。例如:
立即学习“Java免费学习笔记(深入)”;
-
const x: never = someFunctionThatAlwaysThrows(); console.log(x);→ TS 直接报错“不能访问 never 类型” if (val as string) { ... } else if (val as number) { ... } else { /* 此处若 val 是 string | number,则该 else 不可达 */ }
配合 tsc --noEmit --watch,可在保存时实时反馈这类逻辑断点,比纯 JS 工具更早暴露问题。
用构建工具报告反向验证残留逻辑
Tree Shaking 不处理闭包副作用,但构建产物本身可暴露“本不该存在却体积不小”的模块:
- Webpack:开启
optimization.providedExports: true和stats.usedExports: true,检查输出中是否出现"used exports: *"却无导出、体积却不为 0 的模块 - Rollup:运行
rollup -c --treeshake=verify,它会明确指出"Module X has unknown side effects at line Y",比如顶层立即执行函数或事件监听绑定
这类模块虽不属“控制流不可达”,但属于“逻辑上应被删而未删”,是死代码清理的延伸重点。
补充人工排查三类易漏结构
工具再强也有盲区,以下结构常逃过自动检测,需结合代码审查手动识别:
- 立即执行函数:
(() => { init(); })();—— 没 export、没名字,但执行即生效 - 模块级副作用赋值:
let flag = localStorage.getItem('seen');—— 即使后续无任何读取,初始化本身已构成执行痕迹 - 动态注册逻辑:
document.addEventListener('DOMContentLoaded', handler);—— 若 handler 未被其他地方引用,且该模块仅被 import 一次,就极可能是孤立执行入口
这类代码不会被标记为“unreachable”,但属于“无调用链支撑的静默执行”,本质仍是应清理的死逻辑。


















