在計算機上打開 Visual Studio Code,並使用以下代碼創建名為 currency.js
的新文件:
const rates = {}; function setExchangeRate(rate, sourceCurrency, targetCurrency) { if (rates[sourceCurrency] === undefined) { rates[sourceCurrency] = {}; } if (rates[targetCurrency] === undefined) { rates[targetCurrency] = {}; } rates[sourceCurrency][targetCurrency] = rate; rates[targetCurrency][sourceCurrency] = 1 / rate; } function convertToCurrency(value, sourceCurrency, targetCurrency) { const exchangeRate = rates[sourceCurrency][targetCurrency]; return exchangeRate && value * exchangeRate; } function formatValueForDisplay(value) { return value.toFixed(2); } function printForeignValues(value, sourceCurrency) { console.info(`The value of ${value} ${sourceCurrency} is:`); for (const targetCurrency in rates) { if (targetCurrency !== sourceCurrency) { const convertedValue = convertToCurrency(value, sourceCurrency, targetCurrency); const displayValue = formatValueForDisplay(convertedValue); console.info(`- ${convertedValue} ${targetCurrency}`); } } } setExchangeRate(0.88, 'USD', 'EUR'); setExchangeRate(107.4, 'USD', 'JPY'); printForeignValues(10, 'EUR');
要保存該文件,請按“Ctrl+S”(Windows、Linux)或“Cmd+S”(Mac)。
此程序的目標是設置三種貨幣(USD、EUR 和 JPY)之間的匯率。 然后,我們要顯示 10 EUR
對應於其他所有貨幣的價值,精確到小數點后兩位。 對於添加的每種貨幣,應計算與所有其他貨幣的匯率。
創建啟動配置
我們會經常用到調試器,因此讓我們為應用創建一個啟動配置。 在 Visual Studio Code 中,轉到“運行”選項卡,選擇“創建 launch.json 文件”,然后選擇“Node.js”。
這就在項目中創建了文件 .vscode/launch.json
。 可以編輯此文件,以進一步自定義如何啟動程序進行調試。 默認情況下,將創建啟動配置以執行當前打開的文件。 在本示例中,該文件為 currency.js
。
檢查程序入口點的路徑和名稱是否與設置相匹配。
備注
如果要為項目創建不同的啟動配置,選擇“添加配置”。
完成配置准備后,若要選擇它,請使用邊欄頂部的下拉列表。 接下來,要開始調試,請選擇“運行”。
分析問題
現在,要啟動該程序,請選擇“啟動調試”。
應看到程序快速完成。 這是正常的,因為尚未添加任何斷點。
如果沒有顯示調試控制台,若要打開它,請按“Ctrl+Shift+Y”(Windows、Linux)或“Cmd+Shift+Y”(Mac)。 應在調試控制台中看到此文本,后跟一個異常。
The value of 10 EUR is: 11.363636363636365 - 11.363636363636365 USD /app/node-101/currency.js:23 return value.toFixed(2); ^ TypeError: Cannot read property 'toFixed' of undefined at formatValueForDisplay (/app/node-101/currency.js:23:16) at printForeignValues (/app/node-101/currency.js:32:28) at Object.<anonymous> (/app/node-101/currency.js:40:1) at Module._compile (internal/modules/cjs/loader.js:959:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10) at Module.load (internal/modules/cjs/loader.js:815:32) at Function.Module._load (internal/modules/cjs/loader.js:727:14) at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10) at internal/main/run_main_module.js:17:11
此程序所要做的是設置三種貨幣(USD、EUR、JPY)之間的匯率,並顯示 10 EUR
對應於其他所有貨幣的值,精確到小數點后兩位。
在這里可以看到兩個 bug:
- 小數點后不止兩位。
- 程序崩潰並出現異常,無法顯示
JPY
值。
修復位數顯示
首先,我們將解決第一個問題。 由於你沒有編寫此代碼,並且調用了許多不同的函數,因此讓我們首先使用分布執行來了解執行流。
使用斷點並逐步執行
要添加斷點,請單擊 上第 39 行的左邊距。
然后再次啟動調試,並單步執行 printForeignValues()
函數。
檢查變量狀態
現在,使用“變量”窗格檢查不同變量的值。
value
和sourceCurrency
的值是多少?- 你是否在
rates
變量中看到三個預期的項:USD
、EUR
和JPY
?
要繼續單步執行直至設置變量 convertedValue
,請使用“單步跳過”。
應該看到此時該值似乎正確。
進一步看看 displayValue
的值。 它應該包含要顯示的格式化字符串,如我們預期的那樣有兩個數字。
然后我們可以得出結論,到目前為止,函數 convertToCurrency()
和 formatValueForDisplay()
似乎是正確的,並返回了預期的結果。
更正錯誤
繼續單步執行直到 console.info()
調用,並仔細檢查此行。 看到這里的錯誤了嗎?
然后你可以在打印值時使用 displayValue
而不是 convertedValue
來修復第一個 bug。 重啟程序並檢查 USD
值是否正確顯示 11.36
。 第一個問題解決了。
找出崩潰的原因
現在讓我們弄清楚程序崩潰的原因。 刪除當前斷點,並選中“斷點”窗格中的 框,以強制程序在引發異常后暫停。
在調試器中再次運行該程序。 它應在出現異常時暫停,並在編輯器窗口的中間顯示一個大型錯誤日志。
查看執行停止和顯示異常消息 TypeError: Cannot read property 'toFixed' of undefined
的行。 通過該消息可以推斷,value
參數函數的值是 undefined
而不是數字,因此導致了異常。
倒回調用堆棧
你在錯誤消息下面看到的堆棧跟蹤可能有點難以理解。 好消息是,Visual Studio Code 會為你處理函數調用堆棧。 默認情況下,“調用堆棧”窗格中只會顯示有意義的信息。 讓我們使用它來找出導致此異常的代碼。
我們知道 formatValueForDisplay()
引發了異常。 要查看調用它的位置,請在“調用堆棧”窗格中雙擊它下面的函數。 應在 printForeignValues
函數中的此行結束。
const displayValue = formatValueForDisplay(convertedValue);
仔細觀察,你會發現導致異常的參數來自於 convertedValue
變量。 現在,需要找出該值在何時變為 undefined
。
一種選擇是在此行添加一個斷點,並在斷點每次命中該變量時檢查它。 我們不知道何時會發生這種情況,在復雜的程序中,這種方法可能很麻煩。
添加條件斷點
此處最好將調試器設置為僅在 convertedValue
為 undefined
時才在該斷點處停止。 事實上,Visual Studio Code 可以做到這一點。 不通過左鍵單擊在 31
行添加常規斷點,而是右鍵單擊並選擇“添加條件斷點”。
現在可以輸入觸發斷點的條件。 輸入 convertedValue === undefined
,然后按 Enter。 重啟程序,它應在你希望的位置停止。
觀察當前狀態
現在,請花一些時間來分析當前狀態。
- 變量
convertedValue
是convertToCurrency(value, sourceCurrency, targetCurrency)
的結果,因此還要檢查參數的值並確認它們是正確的。 - 具體而言,請查看
value
是否具有預期的值10
。
查看一下 convertToCurrency()
函數的代碼。
function convertToCurrency(value, sourceCurrency, targetCurrency) { const exchangeRate = rates[sourceCurrency][targetCurrency]; return exchangeRate && value * exchangeRate; }
你知道此代碼的結果為 undefined
。 還知道 value
為 10
。 這意味着問題應該出在 exchangeRate
的值。 將鼠標懸停在變量 rates
之上查看該值。
你嘗試獲取 EUR
到 JPY
的匯率,但如果展開 EUR
值,你會發現只有 USD
的轉換率。 缺少 JPY
的轉換率。
修復缺失的轉換率
現在已知缺失某些轉換率,讓我們來了解原因。 要刪除所有現有斷點,請在“斷點”窗格中選擇“刪除所有斷點”。
觀察匯率變量
在程序的開頭第 37
行的 setExchangeRate(0.88, 'USD', 'EUR');
上添加一個斷點。 重啟程序,若要監視 rates
變量的值,請在“監視”窗格中選擇“加號”並輸入 。 每次更新 rates
的值時,其值都會反映在“監視”窗格中。
單步跳過第一個 setExchangeRate()
調用,並查看 rates
上的結果。
此時可以看到 USD
和 EUR
的互匯率相同,符合我們的預期。 現在再單步跳過一次,看看第二次 setExchangeRate()
調用的結果。
你會看到 USD
和 JPY
的互匯率相等,但並未顯示 EUR
和 JPY
之間的匯率。 現在來看看 setExchangeRate()
代碼。
function setExchangeRate(rate, sourceCurrency, targetCurrency) { if (rates[sourceCurrency] === undefined) { rates[sourceCurrency] = {}; } if (rates[targetCurrency] === undefined) { rates[targetCurrency] = {}; } rates[sourceCurrency][targetCurrency] = rate; rates[targetCurrency][sourceCurrency] = 1 / rate; }
最重要的是最后兩行。 看來你找到 bug了! 僅在 sourceCurrency
和 targetCurrency
之間設定了匯率,但還需要計算之前添加的其他貨幣的匯率。
修復代碼
替換以下兩行:
rates[sourceCurrency][targetCurrency] = rate;
rates[targetCurrency][sourceCurrency] = 1 / rate;
替換為此代碼。
for (const currency in rates) { if (currency !== targetCurrency) { // Use a pivot rate for currencies that don't have the direct conversion rate const pivotRate = currency === sourceCurrency ? 1 : rates[currency][sourceCurrency]; rates[currency][targetCurrency] = rate * pivotRate; rates[targetCurrency][currency] = 1 / (rate * pivotRate); } }
使用此代碼,對於 sourceCurrency
和 targetCurrency
以外的每種貨幣,將使用 sourceCurrency
的匯率來推斷另一種貨幣與 targetCurrency
之間的匯率,並相應地進行設置。
備注
只有當 sourceCurrency
和其他貨幣之間的匯率已經存在時,此修復才有效,在本例中,這是一個可以接受的限制。
測試更正
我們來測試一下更改。 刪除所有斷點,然后重啟程序。 現在應在控制台中看到預期的結果,而不會出現任何故障。
The value of 10 EUR is: - 11.36 USD - 1220.45 JPY
就是這樣。 代碼修復了。 現在,你可以使用 Visual Studio Code 高效調試事先不了解的代碼。 干得不錯!