- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
调试(Debugging)是指在一个脚本中找出并修复错误的过程,它是每个前端开发者必须掌握的核心技能。本文基于 zh.javascript.info(现代 JavaScript 教程)仓库中的「代码质量 · 在浏览器中调试」章节展开,结合仓库自带的 调试示例页 与 hello.js 源码,系统讲解如何使用 Chrome(谷歌浏览器)开发者工具:从打开 Sources 面板、设置断点、使用debugger命令暂停脚本,到跟踪执行、检查变量与调用栈,再到用console.log记录日志。学完本章,你将能够独立完成脚本的断点调试、定位逻辑错误,并理解调试器背后「暂停—观察—步进」的核心工作流。
调试是什么,为什么需要调试工具
在编写更复杂的代码之前,先聊聊调试。所有现代浏览器和大多数其他环境都支持调试工具——即开发者工具中的一个特殊用户界面,它让调试变得更加容易。它允许我们一步步地跟踪代码,随时查看当前实际运行的情况,而不是靠猜测或盲目地往代码里塞输出语句。
本教程以 Chrome 为例展开讲解,因为它拥有足够多的功能;其他大部分浏览器(Firefox、Edge、Safari 等)的开发者工具功能与它也基本类似,掌握 Chrome 的操作后可以快速迁移。仓库中该章节位于 1-js/03-code-quality/01-debugging-chrome/article.md,属于「代码质量」篇(见 章节索引)的第一课,目的是在深入学习编码实践之前先解决「如何发现并定位错误」的问题。
准备调试示例:仓库自带的可运行页面
本仓库为该章节准备了两个配套文件,可以直接在浏览器中打开演练:
- 示例页面 index.html:页面通过
<script src="hello.js"></script>引入脚本,并在页面加载时调用hello("John"); - 示例脚本 hello.js:包含两个函数
hello()与say(),它们会依次被调用。
index.html的核心结构如下:
<!DOCTYPE HTML> <html> <body> <script src="hello.js"></script> An example for debugging. <script> hello("John"); </script> </body> </html>hello.js的全部源码如下(注意行号,后面的断点设置会精确到行):
function hello(name) { let phrase = `Hello, ${name}!`; say(phrase); } function say(phrase) { alert(`** ${phrase} **`); }调用链非常简单:页面加载 →hello("John")被调用 → 构造phrase字符串 → 调用say(phrase)→say弹出alert对话框。这个极简的例子足以演示断点、步进与变量检查等全部核心操作,是后面所有调试练习的载体。
打开开发者工具:Sources(资源)面板
在 Chrome 中打开上面的示例页面后,按下快捷键:
- Windows / Linux:
F12 - Mac:
Cmd+Opt+I
即可打开开发者工具,然后选择Sources(资源)面板。首次打开时,界面大致如下(不同 Chrome 版本可能略有差异,但面板位置通常很明显):
界面顶部的切换按钮(Toggle)可以打开/关闭左侧的文件列表选项卡。在文件预览树中点击并选择hello.js,Sources 面板会呈现出三个主要区域:
- 文件导航(File Navigator):列出依附于当前页面的所有文件,包括 HTML、JavaScript、CSS 以及图片等资源,Chrome 扩展程序也会显示在这里;
- 代码编辑(Code Editor):展示当前选中文件的源码,可直接阅读,也可以在断点处高亮当前执行位置;
- JavaScript 调试(JavaScript Debugging):用于调试的区域,包含断点列表、变量观察、调用栈、作用域等工具,我们马上会逐一探索。
如果觉得左侧文件列表占空间,可以再次点击切换按钮将其隐藏,为代码编辑区腾出更多空间。
控制台(Console):随时执行表达式
在 Sources 面板按下Esc键,底部会滑出一个控制台(Console)。在这里输入命令并按Enter即可立即执行,执行结果会显示在下方。
例如:
- 输入
1+2并回车,会返回3; - 输入
hello("debugger")并回车,函数调用执行完毕但没有任何返回值,所以结果是undefined。
控制台是调试过程中最常用的辅助工具之一:当脚本在断点处暂停时,你可以在控制台里直接查看或修改当前作用域内的变量、调用函数,验证假设后继续执行,从而快速缩小问题范围。
断点(Breakpoints):让调试器自动暂停
断点(breakpoint)是调试器会自动暂停 JavaScript 执行的位置。当代码在断点处暂停时,我们可以检查当前变量、在控制台执行命令等——换句话说,我们可以开始「调试」它。
设置断点
继续使用hello.js:
- 在代码编辑区中,点击第 4 行的行号数字(
say(phrase);那一行,注意是点击行号本身,不是点击代码); - 同样地,在第 8 行的行号上再点击一下(
alert(...)那一行)。
设置完成后,第 4 行和第 8 行的行号左侧会显示断点标记,效果如下图(蓝色标记处即断点位置):
管理断点
右侧的「断点列表」面板会汇总所有文件中设置的断点,当项目中有多个文件、多个断点时尤为有用:
- 快速跳转:点击右侧面板中的某个断点,可直接跳到源码中对应的位置;
- 临时禁用:取消选中某个断点前的复选框,即可临时禁用该断点(断点仍在列表中,但不会触发);
- 删除断点:右键单击断点并选择移除,可彻底删除;
- 等等。
条件断点
在行号上右键单击,可以创建一个条件(conditional)断点:只有你提供的表达式为真时,断点才会触发暂停。
例如:在一个循环中,只有当变量 `i` 等于某个特定值时(如 `i === 5`),或者在某个参数为特定值时(如 `name === "admin"`)才暂停执行。这可以避免手动多次点击「恢复」来跳过无关迭代,非常适合在特定变量值或特定参数出现时进行定点排查。"debugger" 命令:在代码中直接指定暂停点
除了在开发者工具里点击行号,我们还可以直接在源码中使用debugger命令来暂停代码,例如把hello.js修改为:
function hello(name) { let phrase = `Hello, ${name}!`; debugger; // <-- 调试器会在这里停止 say(phrase); }当 JavaScript 引擎执行到debugger语句时,如果开发者工具处于打开状态,执行会立即暂停;如果开发者工具没有打开,浏览器会直接忽略该语句,不影响正常运行。因此,debugger命令非常适合在开发阶段临时埋点:无需在 UI 上翻找行号,代码即调试点,逻辑一目了然。调试完成后再删除或注释掉即可。
暂停并查看:Watch、Call Stack 与 Scope
在示例中,hello()函数是在页面加载期间被调用的,因此激活调试器最简单的方式是——在设置好断点后重新加载页面:按下F5(Windows / Linux)或Cmd+R(Mac)。
页面重新加载后,程序会在第 4 行的断点处暂停执行,当前行会被高亮,同时编辑器上方会出现「暂停」状态栏:
暂停后,打开右侧的信息下拉列表(箭头指示的位置),这里有三个核心工具面板,用于查看当前的代码状态:
1. Watch(察看)—— 显示任意表达式的当前值
点击加号+并输入一个表达式(例如变量名、1 + 2、name.toUpperCase()等),调试器会显示它的当前值,并在执行过程中自动重新计算。当我们需要持续观察某个关键变量在多次步进中的变化时,Watch 是最直接的方案。
2. Call Stack(调用栈)—— 显示嵌套的调用链
此时调试器正停在hello()的调用链中:hello()由index.html中的一个脚本调用,由于该调用发生在全局脚本(不在任何函数内),调用栈中显示为"anonymous"(匿名)。
如果点击调用栈中的某一项,调试器会跳到对应的代码位置,并且可以查看该层栈帧的所有变量。在多层函数嵌套调用时,调用栈能清楚回答「我是被谁调进来的」「上一层是什么状态」这两个关键问题。
3. Scope(作用域)—— 显示当前的变量
Local(局部):显示当前函数中的变量;对应变量在源代码中也会以高亮形式标出当前值(例如本例中可以看到name = "John"、phrase = "Hello, John!");Global(全局):显示全局变量(不在任何函数中的变量);- 此外还有
this关键字的值——本教程此阶段尚未讲到this,后续章节会专门学习。
暂停时,这三块面板配合控制台,足以对当前执行环境做一次完整的「体检」。
跟踪执行:逐条语句地观察脚本
暂停之后,我们就可以开始跟踪(stepping)脚本了。右侧面板顶部有一组跟踪按钮,作用如下:
| 按钮 | 名称 | 行为 | 快捷键 |
|---|---|---|---|
| 恢复(Resume) | 继续执行,直到下一个断点(若无其他断点则直接运行完) | F8 | |
| 下一步(Step) | 运行下一条(当前行)指令;若下一条是函数调用,会进入函数内部并在其第一行暂停 | F9 | |
| 跨步(Step over) | 运行下一条指令,但不会进入函数内部,函数调用会「不可见地」整体执行完 | F10 | |
| 步入(Step into) | 与「下一步」类似,但遇到异步函数调用时会进入代码内部并等待 | F11 | |
| 步出(Step out) | 继续执行当前函数内的剩余代码,暂停在调用当前函数的下一行 | Shift+F11 |
(注:表格中的图标在仓库中由 largeIcons.svg 提供,并由 head.html 中的 CSS 类渲染,界面截图见 chrome-sources-debugger-trace-1.svg。)
各按钮的详细行为如下。
恢复(Resume)——F8
继续执行。如果没有其他的断点,程序就会继续跑完,调试器不再控制它。
在示例中:点击「恢复」后,执行会从第 4 行的say(phrase)调用继续,随后命中say()函数内部的第 8 行断点并再次暂停。此时再看右侧的Call Stack,会发现调用信息增加了一层——我们现在已经位于say()内部。
下一步(Step)——F9
运行下一条(即当前行)指令。以示例为例,如果当前停在say(phrase)这一行,点击「下一步」会进入say()函数内部;如果当前在say()内,点击它会执行alert语句(屏幕上会弹出提示框)。一次接一次地点击此按钮,整个脚本的所有语句会被逐个执行。
跨步(Step over)——F10
跟上一条「下一步」类似,但如果下一条语句是函数调用则表现不同。这里的「函数」指的是我们自己写的函数(而不是alert这类内建函数)。
- 「下一步」会进入嵌套函数调用,并在其第一行暂停;
- 「跨步」则对我们不可见地整体执行嵌套函数调用,跳过函数内部,然后在函数调用返回后立即暂停。
如果我们对该函数的内部执行不感兴趣,用「跨步」跳过它会非常高效。
步入(Step into)——F11
和「下一步」类似,但在异步函数调用的情况下表现不同。如果你刚开始学 JavaScript,可以先忽略这个差异——因为我们目前还没有用到异步调用。之后只需记住:
- 「下一步」会忽略异步行为,例如
setTimeout(计划中的函数调用,会过一段时间再执行); - 「步入」会进入异步代码并等待(如果需要)。
步出(Step out)——Shift+F11
继续执行当前函数内的剩余代码,并暂停在调用当前函数的下一行代码处。当我们不小心用「下一步」进入了一个嵌套调用,但对该函数内部并不感兴趣时,用它一步回到外层调用点,非常方便。
两个批量开关
右侧面板顶部还有两个常用的开关按钮:
- 启用/禁用所有断点:批量地打开或关闭全部断点。这个按钮不会影响程序的执行,只是一个断点的总开关,适合临时挂起整套断点策略;
- 出错时自动暂停:启用后,只要开发者工具是打开的,任何脚本执行错误都会导致脚本自动暂停。随后就可以在调试器中分析变量、查看上下文,弄清楚到底哪里出错、出错时的状态是什么。因此,如果脚本因为错误「挂掉」了,可以打开调试器、启用这个选项、重载页面,一步步观察错误发生前的现场。
Continue to here(执行到此处)
在代码中的任意一行上右键单击,弹出的关联菜单(context menu)里有一个非常实用的选项 ——"Continue to here":让程序继续执行直到这一行再暂停。当你想要向前推进很多步、但又不愿专门去设置一个断点时,它是最快捷的选择。
日志记录:用 console.log 留下运行痕迹
调试器并不是观察代码运行的唯一手段。想要向控制台输出信息,可以使用console.log函数。例如,将0到4的值输出到控制台:
// 打开控制台来查看 for (let i = 0; i < 5; i++) { console.log("value", i); }普通用户看不到这些输出——它们只出现在控制台里。查看方式有两种:
- 打开开发者工具中的Console(控制台)选项卡;
- 在任意其他选项卡中按下
Esc键,在下方打开控制台。
如果在代码中留有足够的日志记录,那么即使不借助调试器,我们也能从日志中还原「刚刚发生了什么」。日志适合快速粗排,调试器适合精确定位,两者互为补充。需要提醒的是:上线前的代码里应清理掉不必要的调试日志,避免噪音与敏感信息泄露。
小结:三种暂停脚本的方式与调试工作流
综合全文,共有3 种方式可以让脚本暂停:
- 断点:在开发者工具中点击行号设置,最常用的方式;
debugger语句:直接在源码中写入暂停指令,代码即断点;- error(脚本错误):当开发者工具打开且「出错时自动暂停」开关开启时,任何执行错误都会导致脚本自动暂停。
无论通过哪种方式暂停,之后都可以进行完整的调试动作:检查变量、查看调用栈、跟踪(步进)代码来定位执行出错的位置。这正是浏览器调试的核心工作流:暂停 → 观察 → 步进 → 修复 → 重载验证。
开发者工具中的功能远不止本文介绍的这些。完整的手册可以查阅 Chrome DevTools 官方文档(本文成文时的浏览器版本请以实际界面为准);本章的内容已经足够让你上手代码调试。后续随着浏览器相关的开发越来越多,强烈建议进一步探索开发者工具的高级功能。最后一个小建议:大胆点击开发者工具中的各个区域,看看会显示什么——这可能是学习开发者工具最快的方式,也别忘了右键单击和关联菜单里隐藏的各种快捷能力。
- 文档
- 教程
- 前端
【免费下载链接】zh.javascript.info
现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。
相关推荐
JavaScript教程:Chrome浏览器调试技巧详解
JavaScript教程:Chrome浏览器调试技巧详解 作为JavaScript开发者,掌握调试技巧是必备技能。本文将深入讲解如何在Chrome浏览器中使用开
终极指南:Chrome DevTools MCP 如何在浏览器中运行JavaScript代码
终极指南:Chrome DevTools MCP 如何在浏览器中运行JavaScript代码 Chrome DevTools MCP 是一个革命性的工具,它让您
MCP 服务浏览器控制GUI 自动化开发者工具AI 技能JavaScript调试指南:浏览器中的调试技巧
JavaScript调试指南:浏览器中的调试技巧 前言 调试是每个开发者必须掌握的核心技能。本文将详细介绍如何在浏览器中进行JavaScript调试,帮助你快速
文档/教程前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考