使用 JavaScript Debugger 的精髓除了斷點、逐步執行外,還有各種列表顯示 JavaScript 目前的執行狀態,以及一些關於 Debugger 的設定。
閱讀本篇文章時建議搭配 Demo 頁面 Sources - JavaScript Debugging,效果更佳。
執行程式碼的過程中,若需要不斷查看某個變數的值,可以在 Watch 列表中新增一條 Expression。
加入後每次暫停或逐步執行都會重新執行 Watch 中的 Expression,另外也可以手動按下右方的 Refresh watch expressions
圖示來刷新 Expression。
需要注意的就是 Expression 可能會觸發副作用,關於 Watch 的副作用在 Console - Run JavaScript 中的 Live expression 也有提及,當 Expression 為 Function 時有副作用較易察覺,但若是藏在物件的 Getter 中就很可能被忽略了。
Scope 列表中會顯示目前各個 Scope 可取得的變數值,JavaScript Debugger 中的 Scope 可以簡單歸類為以下幾種:
const
、let
)window.x
取得的屬性(var
)以下列程式碼為例子,假設目前停在 console.log
,試著猜猜看 a、b、c、d、e 在 Scope 列表中會分別被歸類於哪一種 Scope:
var a = 'a';
const b = 'b';
function outer() {
const c = 'c';
function inner() {
const d = 'd';
if (true) {
const e = 'e';
console.log(a, b, c, d, e); // 斷點
}
}
inner();
}
outer();
答案在下方,可以在 Demo 頁面看看實際的執行結果,是否和自己的想法一致呢?注意 function
、var
的宣告是屬於 Function scope,更詳細的說明可以參考 MDN 關於 Functions 和 Block 的文件。
注意變數可能同時屬於多種 Scope,在 Sources 面板的 Scope 列表中會自動歸類到其中一種。
答案是Global, Script, Closure, Local, Block
雙擊變數可以修改變數值,比較特別的是 Function 執行到最後一行的時候 Local scope 會出現 Return value
,可以修改 Return value
的值,甚至 Function 本身的程式碼也可以修改。
另外右鍵點擊 Scope 列表內的 Function 會多一個 Show function definition
選項,可以跳至該 Function 宣告的位置。
每多執行一層 Function,Call stack 就會加入一層 Function,以下方程式碼為例,若在 C 行加入斷點,執行 outer
後會看到 Call stack 裡面出現 hello
、world
:
function hello() {
let message = 'Hello'; // A
function world() {
message = message + ' World'; // C 斷點
console.log(message);
}
inner(); // B
}
Call stack 內的藍色箭頭會指向顯示目前正在觀察的 Function,點擊其他 Function 如 hello
可以看到進入 world
前的狀態:
右鍵點擊任意一層可以看到 Restart frame
選項,點擊後會跳至該 Function 的第一行,以下方程式碼為例子,假設目前停在 C 行,點擊 Step 執行 C 行後,再點擊 Restart Frame
就會跳至 C 行之前。
在
Hello
後面加了兩次World
暫停時可以在 Console 內執行任意 JavaScript,例如修改變數、Console.log
等等,可以存取當下 Scope 內的任意變數。
在 DevTools 的設定中,可以找到 Blackboxing
和 Enable JavaScript source maps
。
Blackboxing 能夠 blackbox 符合特定 Pattern 的檔案,另外勾選 Blackbox content scripts
則可以 Blackbox 所有 Extension 的 Content script,不過想要完全避免 Extension 的干擾,還是開啟無痕模式會比較保險。
Preferences > Sources 內可以開關 JavaScript 的 Source map,預設為開啟,也就是自動讀取 Source map 檔案。
Debug 時可以把某些程式碼加入 Blackbox,也就是黑箱作業,當一個檔案被 Blackbox 後,逐步執行系列就不會跳入該程式碼,不過還是有可能經由斷點暫停在 Blackbox 的程式碼中。
Debug 時可以把有把握的檔案 Blackbox 掉,例如寫過完整測試或皆為 Pure function 的程式碼、第三方套件、Extension 的 Content scripts 等等來減少干擾。
在程式碼中點擊右鍵就會看到 Blackbox script
的選項,也可以透過再次點擊 Stop blackboxing
解除。
目前越來越多網頁的程式碼都會經過處理,實際使用時和開發時看到的並不同,而處理過的程式碼通常會被壓縮,幾乎不能用來 Debug,因此使用 Sources 面板進行 Debug 時常常會需要 Source map 來映射目前執行的程式碼到原始碼上,關於 Source map 更多的介紹可以參考 Sources - Files。
Sources 面板中也有提供 format 的功能,點擊程式碼面板的左下角的Pretty print xxx.js
圖示會開啟另一份經過排版的程式碼,名稱為 xxx.js:formatted
,當程式碼的格式太過混亂或是想要對別人的程式碼做壞事時能大大提升可讀性。
也是因此編輯來自 Formatted 或 Source map 的檔案都是無效的,只有修改原始檔案並存檔才能立即覆寫當前程式碼的行為。
善用 Sources 面板的 JavaScript Debugging 功能可以提升 Debug 的效率,雖然 console.log
真的很誘人,也常常是個好方法,但嘗試一下 Sources 面板或許能夠改變未來的 Debug 方式哦。