JavaScript 压缩器

全球通用工具

粘贴一段脚本,工具会给出行为完全一致的最小版本。范围刻意收得很窄:删除注释,折叠行内的连续空格和制表符,仅此而已。不改任何标识符的名字,不删除任何换行——那是自动分号插入(ASI)的陷阱——字符串、模板或正则没有结束的脚本会被拒绝,并在起始引号处给出插入符,而不是被处理一半。

可以粘贴完整脚本或片段,内容不会被截断。页面初始会载入一份可替换的示例。

`/*!` 注释是许可声明惯例,默认会像压缩文件那样保留。

留空时使用 `bundle.js`,压缩后为 `bundle.min.js`。

边输入边更新。所有计算都在你的浏览器里完成,数据不会离开本机。

压缩后的 JavaScript

-21.3%

一次保守的压缩:删除注释和没有连接作用的空格。输入 9 行变为输出 9 行,删除了 1 条注释。它从未重命名标识符,也从未删除换行,因为这两者都可能悄悄改变程序。

输入
207 B
输出
163 B
节省
44 B
删除的注释
1

压缩后的 JavaScript

/*! danfio sample script */
function greeting(name){

return "Hello, "+name+"!";
}
const users=["ada", "grace"];
users.forEach((u)=>{
console.log(greeting(u));
});

可以复制,也可以下载。框里的字节就是文件里的字节。

刻意没有做的事

  • 没有重命名任何东西:`isEnabled` 仍然是 `isEnabled`,因为缩短它需要全程序分析,而本页不会假装能做。
  • 没有删除任何换行,花括号内部也没有。自动分号插入会把删掉的换行变成一条被改变的语句,而一条语句变了就是 bug。
  • 字符串、模板字面量和正则逐字复制;看起来像除法的 URL(`http://…`)之所以安全,是因为扫描器知道表达式可以从哪里开始。
  • 它只缩小文件,也只承诺这一点:死代码消除和跨行合并属于真正的压缩器。

保守的压缩器值得使用,理由很具体:对本页接受的所有输入,它的输出都保证与输入行为一致,这正是“体积小、安全、不出意外”的含义。页面会打印自己没做什么——不改名、不删死代码、不跨行合并——因为那些正是可能悄悄改变程序的变换,这里一概不猜。

关于这个工具

真正的压缩器会解析程序并重新输出,同时重命名标识符、删除死代码、合并语句。本页没有完整的语句读取能力,做不了这些,只做仅凭词法信息就安全的那一部分:删除注释,折叠一行内的连续空白,并补回那一个防止两个词法单元粘在一起的空格。

它保留每一个换行,因为自动分号插入会把换行当作语句分隔符——在 `let x = 1` 和 `++x` 之间删掉换行,会悄悄改变程序。这些承诺就是这里“保守”的含义,并且会随每个结果一起打印出来。

一切都在标签页里完成:扫描和改写由页面上的 JavaScript 执行,因此一段脚本——往往涉及专有代码或凭据——除了你主动下载的文件之外,不会离开电脑。静态页面已经携带生成页面时用示例算出的真实压缩结果,所以在任何人输入之前它就有用。如果这条诚实的边界对你重要,页面会在每个结果下方印出来。

它是怎么工作的

只删两类,别的一概不动

`//` 行注释和 `/* ... */` 块注释会被删除;位于文件开头的 `/*!` 许可声明可按需保留——这是许可惯例,保留方式与压缩文件一致。一行内的连续空格和制表符折叠成一个空格。整个删除集合就这些,结果面板会分别计数:删掉了多少条注释、多少字节。

其他内容一律不动。不改任何标识符的名字,不删除任何换行,不移动任何语句——这些都需要对整个程序做分析,本页不会假装能做,而且每一种都可能悄悄改变程序,比如改名后的变量发生冲突,或者删掉换行触发自动分号插入。

删除注释也有边界:字符串、模板字面量和正则里的 `//`、`/*` 不是注释。因此扫描器必须先识别这些字面量,再判断注释;顺序反过来,就会把一段代码从中间截断,而错误往往只在某个分支执行时才暴露。

为什么保留每一个换行

JavaScript 的自动分号插入会在源码依赖的位置把换行当作语句分隔符。在 `let x = 1` 和 `++x` 之间删掉换行,两条语句就变成一条——`let x = 1 ++x` 不再能解析,或者更糟,解析成另一种含义。保留每个换行每行只多一个字节,却消除了整类 bug,所以本页选择保留。

这笔取舍是公开说明的:按行处理的压缩器无法合并行或折行表达式,因此输出会比能读懂完整语法的压缩器稍大一些。它换回来的保证是:框里的字节,与输入时的字节行为一致。

字符串、模板、正则,以及救场的那一个空格

字符串、模板字面量和正则都逐字符复制,因为在它们内部空格可能有意义,`/` 也不是除法。扫描器判断一个 `/` 是正则还是除法,靠的是“前一个词法单元之后能否开始一个表达式”——在 `=`、`(`、`,` 或 `return` 之后,`/` 开始一个正则;在变量之后,它是除法。

扫描器还会在两个词法单元本来会粘在一起的位置,补回恰好一个空格:`a - -b` 不能变成 `a--b`,`return x` 不能变成 `returnx`。这一个空格,决定了程序还能不能运行,还是变成了别的含义。

刻意不做什么,以及页面何时拒绝处理

不改名,不删除换行,不删除死代码,不合并语句——这些属于建立在完整语法理解之上的真正压缩器,页面会直接说明,而不是假装能做到。它只缩小文件,也只承诺这一点。改名需要作用域分析,死代码消除需要控制流分析,跨行合并需要完整的语法结构;缺少这些信息时动手,风险远大于省下的字节。

字符串、模板字面量或正则从未结束的脚本,或者块注释从未闭合的脚本,会被拒绝,并在起始引号处给出插入符和一句关于常见原因的提示,因为把半个程序排版出来,会得到看起来合理却无法运行的结果。此时不会产生任何下载。

示例

示例使用页面自带的默认输入,只改设置;下面的结果与你在页面上看到的完全一致。

一段带注释和空格的脚本,变小了

粘贴脚本: /*! (c) 2026 */ function add(a, b) { // the sum return a + b; } const total = add(2, 3); console.log(total);

压缩后的 JavaScript

-17.0%

一次保守的压缩:删除注释和没有连接作用的空格。输入 7 行变为输出 7 行,删除了 1 条注释。它从未重命名标识符,也从未删除换行,因为这两者都可能悄悄改变程序。

输入: 112 B · 输出: 93 B · 节省: 19 B · 删除的注释: 1

`/*!` 许可声明默认保留,行注释被删除。

正则字面量原样保留

粘贴脚本: const re = /a + b/g; const c = a / b; if (m) return x;

压缩后的 JavaScript

-14.8%

一次保守的压缩:删除注释和没有连接作用的空格。输入 3 行变为输出 3 行,删除了 0 条注释。它从未重命名标识符,也从未删除换行,因为这两者都可能悄悄改变程序。

输入: 54 B · 输出: 46 B · 节省: 8 B · 删除的注释: 0

正则逐字符复制,而下一行除法两侧的空格会被整理。

不成对的脚本会被拒绝

粘贴脚本: const s = "unterminated;

这段脚本不成对

第 1 行

字符串字面量没有结束

扫描器在起始引号处停下并给出插入符,不会产生任何下载。

常见问题

我的脚本会被上传到某个地方吗?

不会。扫描和改写在这个标签页里的 JavaScript 中运行,结果面板由页面上已有的内容构建,下载是本地创建的 blob。脚本常常是专有代码或嵌入在某个产品里,因此这里完全不接触服务器。

它会把我的变量改成短名字吗?

不会。重命名一个标识符需要全程序分析——必须证明新名字不与任何东西冲突——而做不到这一点的扫描器,会改掉一处开关名却留下另一处,悄悄改变程序。本页保持每个标识符原样,并在结果下方的列表中说明这一点。

输出能保证与输入行为一致吗?

对本页接受的所有内容,可以。边界正是原因:删除注释和行内空白,给本来会粘在一起的词法单元补上唯一必需的空格,换行、字符串、模板、正则和标识符都逐字复制。这些仅凭词法信息就是安全的,所以只承诺“文件变小了”,别的既不承诺也不声称。

为什么更小的文件不一定能安全上线?

因为体积不是唯一的维度,行为才是关键。删掉换行可能触发自动分号插入,重命名变量可能造成冲突,合并语句可能改变求值顺序。一个保留换行和名字的克制压缩器,省得少一些,风险也小得多,这正是本页公开做出的取舍。

如果我的脚本不成对会怎样?

字符串、模板字面量或正则从未闭合,或者块注释从未结束的脚本,会被拒绝,并在起始引号处给出插入符和一句关于常见原因的提示。不会产生任何下载,因为半个程序不是能上线的文件。

资料来源与统计口径

  • 压缩很保守:删除注释、折叠行内多余空格,并保留每一个换行,因为 JavaScript 会用换行结束语句。
  • 字符串、模板与正则表达式一律原样保留;引号或注释没有闭合的脚本会被拒绝,并给出行号与列号。
  • 页面不会重命名变量或删除代码;全部在你的浏览器里完成,不上传任何内容。

最近复核于 2026-10-07.

本页在您的浏览器本地运行,请保留原文件备份;不涉及财务建议。 阅读完整免责声明。