现代js打包工具的tree shaking作用于模块级导出,局部变量消除实为压缩阶段的dce;其擦除前提包括无副作用、未被引用、所在函数已被摇掉。

现代 JS 打包工具(如 Webpack、Vite、Rollup)不会直接对局部作用域变量做 Tree Shaking,但它们能安全擦除这些变量——前提是变量未产生副作用、未被导出、且未被任何活跃引用链触及。
Tree Shaking 的作用对象是 模块级的导出(export),而非函数或块级作用域内的局部变量。局部变量的消除,实际发生在后续的压缩阶段(如 Terser),属于 Dead Code Elimination(DCE)范畴,不是严格意义上的 Tree Shaking,但常被统称为“摇掉”。
局部变量被安全擦除的关键条件
- 变量声明后从未被读取或调用
- 变量赋值表达式无副作用(例如不修改全局、不触发 setter、不调用有副作用的函数)
- 变量未被闭包捕获、未被 return 或抛出、未被作为参数传入外部函数
- 所在函数本身未被引用(即该函数也已被 Tree Shaking 掉)
例如:
// utils.js
export function useful() {
return 'ok';
}
export function unused() {
const a = 1; // ✅ 无副作用,未读取 → 压缩时删
const b = console.log('side effect!'); // ❌ 有副作用 → 保留整行
const c = { x: 1 }; // ✅ 未使用,无副作用 → 删
return useful(); // 仅这一行生效
}
构建后,unused 函数若未被任何地方 import 或调用,整个函数会被 Tree Shaking 移除;一旦移除,其内部所有局部变量自然消失。
如何让局部变量更大概率被擦除
-
避免无意义赋值
const temp = someHelper(); // 如果 temp 没被用,且 someHelper() 无副作用,整行可删
-
不用 let/const 声明后闲置
function fn() { let x; // ❌ 声明但未赋值/未用 → 多数压缩器仍保留声明(语法合法但冗余) const y = 0; // ✅ 未读取 + 无副作用 → Terser 会删 } -
慎用立即执行或隐式副作用
const result = (function(){ /* do something */ })(); // 若 IIFE 有副作用,整段保留 -
确保所在函数可被摇掉
局部变量能否消失,取决于它所在的函数是否“活”:- 函数是
export的?→ 若未被 import,则函数体连带所有局部变量一并移除 - 函数是内联的(如箭头函数字面量)?→ 若父作用域未引用它,也会被压缩器识别为 dead 并清除
- 函数是
实际验证方式
- 构建后查看
.mjs或.js输出文件(禁用混淆),搜索对应变量名 - 使用
webpack-bundle-analyzer或 Vite 的--debug构建,观察模块是否进入产物 - 在
terser配置中开启compress.drop_console: true等,辅助判断副作用影响
局部变量本身不是 Tree Shaking 的目标,但它依附的函数和语句,只要满足静态可判定“未使用 + 无副作用”,就会在构建链路后半段被彻底清理。关键不在“怎么声明”,而在“是否暴露给模块系统”和“是否引入可观测行为”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











