新手排查 bug,最常用的一招是到处写 console.log,跑完看输出,再删掉。这招能用,但低效又脏:你得像挤牙膏一样一点点打印,还容易漏看。VS Code 自带可视化调试器,能让你暂停程序运行,看清那一刻每个变量的值、函数是怎么一层层调进来的。这一篇带你入门。
把调试想成给跑步的人喊停,然后问他现在心率多少、上一棒是谁交的棒。程序跑飞时,你不需要猜,直接让它停在你关心的那一行看个明白。
先装运行环境
调试前,得让 VS Code 知道怎么运行你的程序。不同语言装对应插件(如 Python、Node 的调试能力已内置或靠插件)。以 Node.js 为例,本身就能被调试;Python 需装 Python 插件。
打断点:让程序在某一行停住
在代码行号左边点一下,出现一个红点,这就是断点(breakpoint)。运行调试时,程序跑到这一行会暂停,交给你检查。
function sum(a, b) {
let total = a + b; // 在这一行左边点红点
return total;
}
console.log(sum(2, 3));
启动调试
- 切到运行和调试视图(左侧播放加虫子的图标),点运行和调试,或按 F5。
- 首次会让你选环境(Node、Python 等),选完生成一份 launch.json 配置。
- 程序跑到断点处自动暂停,编辑器高亮那一行。
调试工具栏:单步执行
暂停后,顶部出现调试工具栏,核心几个按钮:
- 继续(F5):跑向下一个断点。
- 单步跳过(F10):执行当前行,停在下一行(不进函数内部)。
- 单步进入(F11):当前行若调用了函数,就钻进函数内部一行行看。
- 单步退出(Shift+F11):从当前函数里跑完,回到调用它的地方。
- 重启 / 停止:重新来过或结束调试。
新手记住 F10(看这一层)和 F11(钻进函数)这对就够了,绝大多数 bug 靠它们能定位。
看变量:不用打印也能看见
暂停时,几个面板帮你看状态:
- 变量(VARIABLES):自动列出当前作用域里所有变量和它们的值,实时更新。比 console.log 省事——你不用提前想好该打印哪个。
- 监视(WATCH):你手动加一个表达式(如 total * 2),它持续显示这个值的变化。
- 调用栈(CALL STACK):显示是谁调用了谁——main 到 sum,点任意一层能跳回那一刻的上下文。追这个函数怎么被调进来的全靠它。
条件断点:只在特定情况停
如果循环跑了一万次,你只想在第 9999 次停,普通断点会让你点残。右键断点选编辑断点,加条件:
i === 9999
只有条件成立时才暂停。排查某次特定输入才出错的场景极好用。
实战:追踪一个算错的值
假设 sum(2,3) 返回了不对的结果:
- 在 let total = a + b; 打普通断点,F5 跑起来。
- 暂停后看变量面板,a 是 2、b 是 3,但 total 显示 NaN?
- 发现 a 其实是字符串 ‘2’(从输入框来的),‘2’ + 3 变成拼接而非相加。
- 改成 Number(a) + Number(b),问题解决——全程没写一个 console.log。
常见新手坑
- 只用 console.log 排查:效率低、易留脏代码,复杂逻辑还是得靠断点。
- 忘了装语言插件就调试:调试器启动不了或没反应。
- 条件断点写错表达式:永远不触发,以为程序没问题,其实没停对地方。
- 调试完忘了删断点:下次跑一堆红点,干扰思路。调试完清理一下。
小测验
- 问题1:想看函数内部是怎么执行的,用 F10 还是 F11?答案:F11(单步进入),F10 会跳过函数内部。
- 问题2:变量面板和 console.log 比,优势在哪?答案:自动列出当前作用域所有变量值,不用你提前想好打印哪个。
- 问题3:循环一万次只想在第 9999 次暂停,怎么办?答案:用条件断点,设条件 i === 9999。
更多实战:用调试修一个真实 bug
假设一个函数该返回 5 却返回了 3:
function add(a, b) {
let result = a + b;
result = result - 1; // 这行是上次调试遗留的多余代码
return result;
}
打条件断点在 result = result - 1,跑起来暂停后看”变量”面板:a=2、b=3、result 先变 5 再被减成 4——立刻定位到那行多余代码。删掉它,问题解决。全程没写一个 console.log。
监视表达式的妙用
在”监视”面板加 a + b,程序单步时它能实时显示这个表达式的当前值。当你怀疑某个计算算错了,把可疑表达式加进监视,比在代码里插打印更干净,查完删掉即可。
自测:你真的懂了吗
- 想看函数内部执行用 F10 还是 F11?答案:F11(单步进入),F10 会跳过函数内部。
- 变量面板比 console.log 优势?答案:自动列出当前作用域所有变量值,不用提前想好打印哪个。
- 循环一万次只想第 9999 次暂停怎么办?答案:条件断点,设
i === 9999。
常见认知误区
调试这块,最大的误区就是”只用 console.log”。满屏打印既低效又脏,复杂逻辑还是得靠断点。第二个误区是”调试前不装语言插件”——调试器启动不了或没反应,往往是因为对应语言的运行环境或插件没装好。第三个误区是”条件断点乱设”——表达式写错导致永远不触发,以为程序没问题,其实压根没停对地方,设完先确认表达式合理。第四个误区是”调试完不删断点”——下次跑一堆红点干扰思路,调试完顺手清理。第五个误区是”怕用调试器,觉得复杂”——其实核心就 F5 继续、F10 单步跳过、F11 单步进入三个键,掌握它们就能解决绝大多数问题,比到处插打印强太多。把调试器当放大镜,程序跑飞时让它停在你关心的那一行看个明白。
这一篇你该记住的
- 调试器让你暂停程序、看清那一刻的状态,比打印高效干净。
- 红点等于断点;F5 继续、F10 单步跳过、F11 单步进入。
- 变量面板看实时值,监视面板盯表达式,调用栈看谁调谁。
- 条件断点只在特定情况暂停,适合循环和特定输入。
- 调试完记得清理断点。
下一篇我们讲集成终端与重构:在编辑器里直接跑命令、用重命名与提取函数等重构手段安全改代码。