概覽#
這是 Console 系列的最後一章,重點放在「在 Console panel 裡執行 JavaScript」的細節:換行縮排、Autocomplete、Default Async、Context 切換、Live Expression。這些功能都不大,但組合起來會把 Console 從「印 log 的地方」升級成「真正能拿來工作的 REPL」。
換行與縮排#
剛開始在 Console 輸入多行程式碼很不順:要不是手動縮排,要不就是還沒打完不小心按 Enter 直接執行噴錯。但 Console 其實比想像中聰明,搞懂規則後輸入效率會大幅提升。
預設行為:
Enter:執行Shift+Enter:換行
但 Console 會根據語法判斷該不該執行:
- 如果輸入了一個 statement,或剛打完
{,按Enter會「自動換行」而不是執行 - 一直到 statement 結束、或遇到對應的
},按Enter才會真正執行 - 前提:游標必須在 Console 的「最後一行」
換句話說,輸入 if (...) 後 Enter,Console 會自動進入續行模式,直到 } 配對結束。
如果要編輯中間的某段已輸入內容,建議先把後半段剪下,編輯完前面再貼回來,避免游標不在最後一行而觸發執行。
statement 可以簡單理解為「不會回傳值」的程式碼,例如:
if (condition) {
...
}
for (let i = 0; i < 100; i++) {
...
}
function test() {
...
}Rerun 與 Autocomplete#
輸入程式碼時跳出的下拉選單包含兩種來源:
- 目前 context 中可用的變數
- 曾經輸入過的歷史指令(前面有
>標示)
按方向鍵上下也可以瀏覽過去輸入過的程式碼,跟 terminal history 一樣。
如果歷史紀錄太雜、不想出現在 autocomplete 裡,有兩個處理方式:
- Console settings 取消
Autocomplete from history - 在 Console 內按右鍵 ➡️
Clear console history
另外有個小細節:輸入 JavaScript 內建函式時打到 (,DevTools 會跳出簡單的參數提示,不用每次都試誤或開 MDN。
Default Async#
如果用過 async / await 語法,應該知道 await 只能在 async function 裡面用。但 ⋯
在 Console 內可以「直接使用」await,不需要外層包 async function。
以前要用 await 必須包一個立即函式(IIFE):
(async () => {
console.log("zzz...");
await sleep(1000);
console.log("Wake up!!");
})();現在直接這樣寫就行:
console.log("zzz...");
await sleep(1000);
console.log("Wake up!!");對於試 fetch、Promise、各種非同步 API,省下大量樣板程式碼。
Context#
網頁中可能同時存在多個 context,常見的有:
- 主 frame(top frame)
iframe- 瀏覽器 Extension 注入的 script
- Service Worker
Console panel 上方的 Context 選單可以列出所有可用 context,點選後就會切到該 context 執行 JavaScript。這就能做到:操作 iframe 內的元素、和 Extension 或 Service Worker 互動等等。
預設情況下,top frame 沒辦法直接存取 iframe 內定義的變數(被 same-origin policy 保護)。要 debug iframe 內的東西,必須切到該 iframe 的 context。
打開 Context 選單時,hover 到某個
iframecontext,頁面上對應的iframe區塊會亮起來,方便辨識來源。
Live Expression#
Console 上方有一個眼睛圖示,這是 Live Expression。需要持續觀察某個變數值如何變化時,按下圖示新增一組表達式,那個值就會被釘在 Console 最上方即時更新,省得不停手動執行。
但要注意:Live Expression 「會」觸發副作用。它的機制比較像 setInterval,以特定頻率重新執行表達式並更新顯示,跟前一章提到的 Eager Evaluation 不一樣(Eager Evaluation 偵測到副作用就會跳過預覽)。
舉個經典例子,怎麼讓 a == 1 && a == 2 同時為 true:
const a = {
i: 1,
toString() {
return this.i++;
},
};這個物件的 toString 每次被呼叫都會把 i 自增。在 Console 直接輸入 a == 1 時,因為 Eager Evaluation 偵測到副作用,不會出現預覽(嚴格模式(Strict Mode)下也不會);但 a === 1 沒有 type coercion,不會呼叫 toString,所以會有預覽。
如果把 a == 1 加進 Live Expression,就會看到 a.i 的值不斷被往上加,因為 Live Expression 會持續呼叫表達式 ➡️ 持續呼叫 toString ➡️ 持續 this.i++。
用 Live Expression 觀察值時要注意它對表達式的副作用,避免「看的動作改變了被看的東西」。
銜接#
Console 系列到此告一段落。接下來的章節進入 Sources panel:JavaScript Debugging 的重頭戲,包含 Source Map、Workspace、Breakpoint、Step-by-Step 執行等等。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10242319