像“開掛”一樣的 JavaScript 調(diào)試術(shù)
你肯定也遇到過:應(yīng)用行為怪異、你卻只能猜。后來我把 DevTools 的幾種斷點用熟了,調(diào)試忽然不再靠運氣,而是可控、可重復。
這篇帶你用逐類斷點(行斷點、條件斷點、Logpoint、DOM 變更、XHR/Fetch、事件監(jiān)聽、異常、函數(shù)斷點)系統(tǒng)排錯,順手拯救生產(chǎn)力。
一、練手項目(自帶幾個小 Bug)
我們寫個最簡表單,順便用各種斷點把它的小問題揪干凈。
<!DOCTYPE html>
<html>
<head>
<title>Buggy Form</title>
<style>
.error { color: red; }
.success { color: green; }
</style>
</head>
<body>
<form id="signupForm">
<input type="text" id="username" placeholder="Username">
<input type="email" id="email" placeholder="Email">
<button type="submit">Submit</button>
<p id="message"></p>
</form>
<script>
const form = document.getElementById('signupForm');
const username = document.getElementById('username');
const email = document.getElementById('email');
const message = document.getElementById('message');
function validateForm() {
let isValid = true;
if (username.value.length < 3) {
message.textContent = 'Username too short';
isValid = false;
}
if (!email.value.includes('@')) {
message.textContent = 'Invalid email';
isValid = false;
}
return isValid;
}
form.addEventListener('submit', (e) => {
e.preventDefault();
if (validateForm()) {
message.textContent = 'Success!';
message.className = 'success';
} else {
message.className = 'error';
}
});
// Bug:無論是否通過校驗都會發(fā)請求(應(yīng)只在合法時發(fā)送)
fetch('https://api.example.com/submit', {
method: 'POST',
body: JSON.stringify({ username: username.value, email: email.value })
});
</script>
</body>
</html>運行方式(隨手起個本地服務(wù)器):
python3 -m http.server
二、行斷點(Line-of-Code Breakpoint)
場景:精確卡住執(zhí)行點,觀察當前作用域里的變量與控制流。
如何設(shè)置

- 打開 DevTools(F12 / Ctrl+Shift+I)→ Sources
- 找到內(nèi)聯(lián)腳本,在
validateForm里點左側(cè) 行號(如if (username.value.length < 3)那行) - 出現(xiàn)藍色標記即設(shè)置成功
調(diào)試刷新,用戶名填 ab 提交;會在該行暫停。懸停看 username.value 是 ab,F(xiàn)10 單步可見 isValid=false。 你會注意到:文案會被后續(xù)校驗覆蓋,而**fetch 居然仍然會發(fā)**。
真實用例定位購物車“加購失敗”,就在加購那一行卡斷點,看狀態(tài)/入?yún)⑹欠裾!?/span>
三、條件斷點(Conditional Breakpoint)
場景:只在滿足條件時觸發(fā)暫停,避免“每次都卡住”。
如何設(shè)置

- 右鍵剛才的行斷點 → Edit breakpoint → 寫入條件:
username.value.length < 3
填 ab 會停、填 alice 不會停。
調(diào)試 & 修復暫停時發(fā)現(xiàn) message.textContent 會被后續(xù) email 校驗二次覆蓋。改為收集多條消息后統(tǒng)一顯示:
function validateForm() {
let isValid = true;
const messages = [];
if (username.value.length < 3) {
messages.push('Username too short');
isValid = false;
}
if (!email.value.includes('@')) {
messages.push('Invalid email');
isValid = false;
}
message.textContent = messages.join(', ');
return isValid;
}真實用例聊天應(yīng)用里僅對缺失 userId 的消息打斷點,追蹤“消息消失”的根因。
四、Logpoint(只打印,不暫停)
場景:不打亂執(zhí)行節(jié)奏,又想 臨時埋點 看值。
如何設(shè)置

- 在設(shè)置斷點那行右鍵 → Add logpoint → 填
console.log('Message set to:', message.textContent)
提交表單,Console 會打印值變化軌跡,驗證“被覆蓋”的問題。
真實用例價格計算異常?在計算行加 Logpoint,看是否重復計算或順序錯誤。
五、DOM 變更斷點(Break on…)
場景:元素的屬性/子樹被改動時暫停。非常適合“UI 為什么被偷偷改了”。
如何設(shè)置

- Elements 面板選中
<p id="message">→ 右鍵 Break on → Attribute modifications → 再次提交
調(diào)試會在 message.className 變化處停下;棧里能看到發(fā)生在 submit 處理器內(nèi)。配合我們新的消息聚合邏輯,確保類名正確對應(yīng)狀態(tài)。
真實用例圖表數(shù)據(jù)“自己變了”?對圖表容器屬性/子樹變更打斷點,捕捉何時被改。
六、XHR / Fetch 斷點
場景:網(wǎng)絡(luò)請求什么時候發(fā)、為什么發(fā),一目了然。
如何設(shè)置

- Sources → 展開 XHR/fetch Breakpoints → 點擊 + → 填
api.example.com→ 刷新
調(diào)試 & 修復會發(fā)現(xiàn) fetch 在 校驗外部就觸發(fā)了。把它移入“通過校驗”分支:
form.addEventListener('submit', (e) => {
e.preventDefault();
if (validateForm()) {
message.textContent = 'Success!';
message.className = 'success';
fetch('https://api.example.com/submit', {
method: 'POST',
body: JSON.stringify({ username: username.value, email: email.value })
});
} else {
message.className = 'error';
}
});真實用例天氣頁面“老數(shù)據(jù)”?對接口打斷點,核對請求時機與參數(shù)是否正確。
七、事件監(jiān)聽斷點(Event Listener Breakpoints)
場景:按鈕/提交等事件是否觸發(fā)、被誰攔截,一卡便知。
如何設(shè)置
666666
- Sources 面板 → 展開 Event Listener Breakpoints
- 勾選 Control → submit → 點擊提交
調(diào)試在提交回調(diào)里停住,單步確認事件確實觸發(fā)且值如預(yù)期。
真實用例游戲里“跳躍”鍵延遲?對 click/keydown 打斷點,看看是否被別的監(jiān)聽拖慢。
八、異常斷點(Pause on Exceptions)
場景:應(yīng)用“莫名崩潰/靜默失敗”,直接在拋出點停下。
如何設(shè)置
- Sources 頂部勾選 Pause on uncaught exceptions(必要時也勾 caught)
- 重現(xiàn)錯誤,代碼在拋出處暫停
注意:瀏覽器內(nèi)部拋出的某些異常(例如
fetch的net::ERR_NAME_NOT_RESOLVED)不會被該選項捕獲。
真實用例支付流程失敗卻無提示?開異常斷點,定位讀取支付數(shù)據(jù)的錯誤源。
九、函數(shù)斷點(debug(fn))
場景:某函數(shù)被意外頻繁調(diào)用,想每次進來都停一下。
如何設(shè)置
- Console 輸入:
debug(validateForm) - 多次提交,函數(shù)每次調(diào)用都會暫停
真實用例搜索框“自己刷新”?對搜索函數(shù)加 debug,看是什么時機觸發(fā)它。
十、收官
以前我把 DevTools 當“豪華 console”。把這些斷點玩熟后,調(diào)試的感覺像從“摸黑猜”升級到“透視眼”:什么時候、在哪里、為什么發(fā)生,一停就清。
下次遇到怪問題,別再滿屏 console.log。 按場景選對斷點,快、準、穩(wěn)地把 Bug 摁住。





























