在編寫更複雜的代碼前,讓我們先來聊聊調試吧。
調試 是指在壹個腳本中找出並修複錯誤的過程。所有的現代浏覽器和大多數其他環境都支持調試工具 —— 開發者工具中的壹個令調試更加容易的特殊用戶界面。它也可以讓我們壹步步地跟蹤代碼以查看當前實際運行情況。
在這裏我們將會使用 Chrome(谷歌浏覽器),因爲它擁有足夠多的功能,其他大部分浏覽器的功能也與之類似。
妳的 Chrome 版本可能看起來有壹點不同,但是它應該還是處于很明顯的位置。
在 Chrome 中打開 示例頁面。
使用快捷鍵F12(Mac:Cmd+Opt+I)打開開發者工具。
選擇 Sources(資源)
面板。
如果妳是第壹次這麽做,那妳應該會看到下面這個樣子:
切換按鈕 會打開文件列表的選項卡。
讓我們在預覽樹中點擊和選擇 hello.js
。這裏應該會如下圖所示:
資源(Sources)面板包含三個部分:
文件導航(File Navigator) 區域列出了 HTML、JavaScript、CSS 和包括圖片在內的其他依附于此頁面的文件。Chrome 擴展程序也會顯示在這。
代碼編輯(Code Editor) 區域展示源碼。
JavaScript 調試(JavaScript Debugging) 區域是用于調試的,我們很快就會來探索它。
現在妳可以再次點擊切換按鈕 隱藏資源列表來給代碼騰出壹些空間。
如果我們按下Esc,下面會出現壹個控制台,我們可以輸入壹些命令然後按下Enter來執行。
語句執行完畢之後,其執行結果會顯示在下面。
例如,1+2
將會返回 3
,而 hello("debugger")
函數調用什麽也沒返回,所以結果是 undefined
:
我們來看看 示例頁面 發生了什麽。在 hello.js
中,點擊第 4
行。是的,就點擊數字 "4"
上,不是點擊代碼。
恭喜妳!妳已經設置了壹個斷點。現在,請在第 8
行的數字上也點擊壹下。
看起來應該是這樣的(藍色是妳應該點擊的地方):
斷點 是調試器會自動暫停 JavaScript 執行的地方。
當代碼被暫停時,我們可以檢查當前的變量,在控制台執行命令等等。換句話說,我們可以調試它。
我們總是可以在右側的面板中找到斷點的列表。當我們在數個文件中有許多斷點時,這是非常有用的。它允許我們:
快速跳轉至代碼中的斷點(通過點擊右側面板中的對應的斷點)。
通過取消選中斷點來臨時禁用對應的斷點。
通過右鍵單擊並選擇移除來刪除壹個斷點。
……等等。
條件斷點
在行號上 右鍵單擊 允許妳創建壹個 條件 斷點。只有當給定的表達式(妳創建條件斷點時提供的表達式)爲真時才會被觸發。
當我們需要在特定的變量值或參數的情況下暫停程序執行時,這種調試方法就很有用了。
我們也可以使用 debugger
命令來暫停代碼,像這樣:
function hello(name) { let phrase = `Hello, ${name}!`; debugger; // <-- 調試器會在這停止 say(phrase); }
這樣的命令只有在開發者工具打開時才有效,否則浏覽器會忽略它。
在我們的例子中,hello()
函數在頁面加載期間被調用,因此激活調試器的最簡單的方法(在我們已經設置了斷點後)就是 —— 重新加載頁面。因此讓我們按下F5(Windows,Linux)或Cmd+R(Mac)吧。
設置斷點之後,程序會在第 4 行暫停執行:
請打開右側的信息下拉列表(箭頭指示出的地方)。這裏允許妳查看當前的代碼狀態:
察看(Watch)
—— 顯示任意表達式的當前值。
妳可以點擊加號 +
然後輸入壹個表達式。調試器將顯示它的值,並在執行過程中自動重新計算該表達式。
調用棧(Call Stack)
—— 顯示嵌套的調用鏈。
此時,調試器正在 hello()
的調用鏈中,被 index.html
中的壹個腳本調用(這裏沒有函數,因此顯示 “anonymous”)
如果妳點擊了壹個堆棧項,調試器將跳到對應的代碼處,並且還可以查看其所有變量。
作用域(Scope)
—— 顯示當前的變量。
Local
顯示當前函數中的變量,妳還可以在源代碼中看到它們的值高亮顯示了出來。
Global
顯示全局變量(不在任何函數中)。
這裏還有壹個 this
關鍵字,目前我們還沒有學到它,不過我們很快就會學習它了。
現在是 跟蹤 腳本的時候了。
在右側面板的頂部是壹些關于跟蹤腳本的按鈕。讓我們來使用它們吧。
—— “恢複(Resume)”:繼續執行,快捷鍵F8。
繼續執行。如果沒有其他的斷點,那麽程序就會繼續執行,並且調試器不會再控制程序。
我們點擊它壹下之後,我們會看到這樣的情況:
執行恢複了,執行到 say()
函數中的另外壹個斷點後暫停在了那裏。看壹下右邊的 “Call stack”。它已經增加了壹個調用信息。我們現在在 say()
裏面。
—— “下壹步(Step)”:運行下壹條(即當前行)指令,快捷鍵F9。
運行下壹條語句。如果我們現在點擊它,alert
會被顯示出來。
壹次接壹次地點擊此按鈕,整個腳本的所有語句會被逐個執行。
—— “跨步(Step over)”:運行下壹條(即當前行)指令,但 不會進入到壹個函數中,快捷鍵F10。
跟上壹條命令“下壹步(Step)”類似,但如果下壹條語句是函數調用則表現不同。這裏的函數指的是:不是內建的如 alert
函數等,而是我們自己寫的函數。
如果我們對比壹下,“下壹步(Step)”命令會進入嵌套函數調用並在其第壹行暫停執行,而“跨步(Step over)”對我們不可見地執行嵌套函數調用,跳過了函數內部。
執行會在該函數調用後立即暫停。
如果我們對該函數的內部執行不感興趣,這命令會很有用。
—— “步入(Step into)”,快捷鍵F11。
和“下壹步(Step)”類似,但在異步函數調用情況下表現不同。如果妳剛剛才開始學 JavaScript,那麽妳可以先忽略此差異,因爲我們還沒有用到異步調用。
至于之後,只需要記住“下壹步(Step)”命令會忽略異步行爲,例如 setTimeout
(計劃的函數調用),它會過壹段時間再執行。而“步入(Step into)”會進入到代碼中並等待(如果需要)。詳見 DevTools 手冊。
—— “步出(Step out)”:繼續執行到當前函數的末尾,快捷鍵Shift+F11。
繼續執行當前函數內的剩余代碼,並暫停在調用當前函數的下壹行代碼處。當我們使用 偶然地進入到壹個嵌套調用,但是我們又對這個函數不感興趣時,我們想要盡可能的繼續執行到最後的時候是非常方便的。
—— 啓用/禁用所有的斷點。
這個按鈕不會影響程序的執行。只是壹個批量操作斷點的開/關。
—— 啓用/禁用出現錯誤時自動暫停腳本執行。
當啓動此功能,如果開發者工具是打開著的時候,任何腳本執行錯誤都會導致該腳本執行自動暫停。然後我們可以在調試器中分析變量來看壹下什麽出錯了。因此如果我們的腳本因爲錯誤挂掉的時候,我們可以打開調試器,啓用這個選項然後重載頁面,查看壹下哪裏導致它挂掉了和當時的上下文是什麽。
Continue to here
在代碼中的某壹行上右鍵,在顯示的關聯菜單(context menu)中點擊壹個非常有用的名爲 “Continue to here” 的選項。
當妳想要向前移動很多步到某壹行爲止,但是又懶得設置壹個斷點時非常的方便。
想要輸出壹些東西到控制台上?console.log
函數可以滿足妳。
例如:將從 0
到 4
的值輸出到控制台上:
// 打開控制台來查看 for (let i = 0; i < 5; i++) { console.log("value", i); }
普通用戶看不到這個輸出,它是在控制台裏面的。要想看到它 —— 要麽打開開發者工具中的 Console(控制台)選項卡,要麽在壹個其他的選項卡中按下Esc:這會在下方打開壹個控制台。
如果我們在代碼中有足夠的日志記錄,那麽我們可以從記錄中看到剛剛發生了什麽,而不需要借助調試器。
我們可以看到,這裏有 3 種方式來暫停壹個腳本:
斷點。
debugger
語句。
error(如果開發者工具是打開狀態,並且按鈕 是開啓的狀態)。
當腳本執行暫停時,我們就可以進行調試:檢查變量,跟蹤代碼來查看執行出錯的位置。
開發人員工具中的選項比本文介紹的多得多。完整的手冊請點擊這個鏈接查看:https://developers.google.com/web/tools/chrome-devtools。
本章節的內容足夠讓妳上手代碼調試了,但是之後,尤其是妳做了大量關于浏覽器的東西後,推薦妳查看上面那個鏈接中講的開發者工具更高級的功能。
對了,妳也可以點擊開發者工具中的其他地方來看壹下會顯示什麽。這可能是妳學習開發者工具最快的方式了。不要忘了還有右鍵單擊和關聯菜單喲。