JavaScript – 錯誤與除錯(Error Handling & Debugging)
主題:console.log / console.error
簡介
在 JavaScript 開發的過程中,除錯永遠是不可或缺的環節。即使是最簡單的程式,也可能因為變數未定義、型別不符或非同步流程的誤用而產生錯誤。若沒有適當的訊息輸出,開發者往往只能靠「猜測」與「靜默失敗」來定位問題,這不但浪費時間,也會降低程式的可維護性。
console 物件提供了多種方法讓我們 即時觀察程式執行狀態,其中最常用的就是 console.log(一般訊息)與 console.error(錯誤訊息)。透過正確的使用方式,我們可以在瀏覽器開發者工具或 Node.js 終端機上快速取得變數內容、流程走向,甚至在正式上線前就把潛在的錯誤先捕捉到。
本篇文章將從 概念、實作範例、常見陷阱與最佳實踐,再到 實務應用,完整說明如何善用 console.log、console.error 來提升除錯效率,適合 初學者到中級開發者 閱讀與實踐。
核心概念
1. console 物件概覽
console 是瀏覽器與 Node.js 內建的全域物件,提供多種輸出方法:
| 方法 | 目的 | 特色 |
|---|---|---|
console.log() |
輸出一般訊息 | 支援多參數、字串佔位、樣式 |
console.error() |
輸出錯誤訊息 | 會以紅色文字(或 stderr)呈現 |
console.warn() |
警告訊息 | 以黃色文字顯示 |
console.table() |
表格化資料 | 方便檢視陣列或物件集合 |
console.group() / console.groupEnd() |
分組顯示 | 讓訊息層次更清晰 |
console.time() / console.timeEnd() |
計時 | 測量程式碼執行時間 |
在本篇重點聚焦於 console.log 與 console.error,但了解其他方法有助於建立完整的除錯工具箱。
2. console.log 的基本用法
- 單一參數:直接印出字串、數字、布林或物件。
- 多參數:以逗號分隔,可同時顯示多個值。
- 字串佔位:使用
%s(字串)、%d(數字)、%o(物件)等佔位符,讓訊息更具可讀性。 - 樣式:在瀏覽器開發者工具中,可透過
%c加上 CSS 樣式,改變文字顏色、字型等。
// 單一參數
console.log('Hello, World!');
// 多參數
const name = 'Alice';
const age = 28;
console.log('使用者資訊:', name, age);
// 字串佔位
console.log('使用者 %s 的年齡是 %d 歲', name, age);
// 加樣式(僅在瀏覽器有效)
console.log('%c重要訊息:%c 這是一段紅字', 'color: blue; font-weight: bold;', 'color: red;');
3. console.error 的使用時機
console.error 會把訊息送到 錯誤輸出流(stderr),在瀏覽器裡會以紅色字體呈現,在 Node.js 中則會寫入 process.stderr。適合在以下情況使用:
- 捕捉例外(
try...catch)後的錯誤資訊。 - 手動拋出自訂錯誤訊息,提醒開發者或測試人員。
- 在測試環境中標示失敗的測試案例。
function divide(a, b) {
if (b === 0) {
console.error('除數不能為 0!', { a, b });
return NaN;
}
return a / b;
}
divide(10, 0);
4. 進階技巧:使用 console.group 讓訊息層次分明
在除錯較大型的程式時,訊息往往會堆疊成一長串,難以快速定位。console.group() 可以把相關訊息「收合」起來,點擊展開即可查看。
function fetchUser(id) {
console.group(`📦 fetchUser(${id})`);
console.log('開始請求...');
// 假設此處有非同步呼叫
setTimeout(() => {
console.log('收到回應:', { id, name: 'Bob' });
console.groupEnd();
}, 500);
}
fetchUser(123);
5. 透過 console.table 檢視陣列或物件集合
當需要觀察大量資料時,console.table 能把陣列或物件以表格形式展示,讓欄位與列的對應更直觀。
const users = [
{ id: 1, name: 'Amy', age: 24 },
{ id: 2, name: 'Ben', age: 30 },
{ id: 3, name: 'Cindy', age: 27 },
];
console.table(users);
程式碼範例(實用示例 5 個)
範例 1:基本除錯 – 變數檢查
function calculateTotal(price, quantity) {
console.log('price:', price, 'quantity:', quantity); // 觀察輸入值
return price * quantity;
}
calculateTotal(120, 3);
範例 2:使用佔位與樣式提升可讀性
const apiUrl = 'https://api.example.com';
const method = 'GET';
console.log('%c[API] %s %s', 'color: teal; font-weight: bold;', method, apiUrl);
範例 3:捕捉例外並輸出錯誤訊息
try {
JSON.parse('this is not JSON');
} catch (e) {
console.error('JSON 解析失敗!', e);
}
範例 4:分組顯示非同步流程
async function loadData() {
console.group('🔄 loadData');
console.log('開始載入…');
const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const data = await res.json();
console.log('取得資料:', data);
console.groupEnd();
}
loadData();
範例 5:表格化 API 回傳資料
fetch('https://jsonplaceholder.typicode.com/users')
.then(r => r.json())
.then(users => {
console.table(users.map(u => ({
ID: u.id,
姓名: u.name,
電子郵件: u.email,
城市: u.address.city,
})));
})
.catch(err => console.error('取得使用者失敗', err));
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
忘記移除 console.log |
上線前留下大量除錯訊息會影響效能與安全性。 | 使用 Lint(如 ESLint)設定 no-console 規則,或在建置流程中自動移除。 |
| 錯誤訊息與一般訊息混用 | console.log 與 console.error 混在一起,難以分辨真正的錯誤。 |
分層輸出:錯誤使用 console.error,資訊使用 console.log、console.warn。 |
| 過度印出大型物件 | 印出過大的陣列或物件會卡住開發者工具。 | 使用 console.table、JSON.stringify(obj, null, 2) 或只印出關鍵屬性。 |
| 在生產環境直接顯示機密資訊 | 把 API 金鑰、密碼等資訊寫入 console.log,會被使用者看到。 |
永遠不要在除錯訊息中暴露機密資訊;使用環境變數與條件編譯。 |
| 缺少上下文說明 | 單純印出變數值,無法快速了解它屬於哪個流程。 | 加上 標籤或 分組 (console.group) 來提供上下文。 |
最佳實踐清單
- 區分訊息等級:
log、info、warn、error各司其職。 - 使用佔位符與樣式:讓訊息在視覺上更突出。
- 在非同步程式中加入分組:方便追蹤 Promise、async/await 的執行順序。
- 結合 Lint 工具自動偵測:在 CI 流程中確保不會遺漏除錯訊息。
- 針對不同環境設定輸出:開發環境保留完整除錯資訊,上線環境僅保留必要的錯誤報告。
實際應用場景
1. 前端 UI 開發:追蹤使用者互動
在開發表單驗證或 UI 動畫時,常需要即時觀察事件參數。使用 console.log 搭配 event 物件,可快速確認觸發條件。
document.getElementById('submitBtn').addEventListener('click', e => {
console.log('按鈕被點擊 - 事件資訊:', e);
});
2. API 串接:偵測錯誤回應
當前端向後端發送請求時,若回傳錯誤代碼,使用 console.error 能在開發者工具中立即提示。
fetch('/api/orders')
.then(r => {
if (!r.ok) {
console.error('API 錯誤!狀態碼:', r.status);
throw new Error('Network response was not ok');
}
return r.json();
})
.then(data => console.log('訂單資料:', data))
.catch(err => console.error('取得訂單失敗', err));
3. Node.js 後端服務:記錄錯誤與效能
在伺服器端,我們可以把 console.error 的訊息導向日誌檔,配合 process.on('uncaughtException') 捕捉未處理的例外。
process.on('uncaughtException', err => {
console.error('未捕捉的例外:', err);
// 可在此寫入外部日誌系統
process.exit(1);
});
4. 單元測試:顯示失敗原因
使用測試框架(如 Jest)時,若測試失敗,console.error 能把錯誤資訊直接呈現在測試報告中,協助定位問題。
test('divide 函式應拋出錯誤', () => {
expect(() => divide(5, 0)).toThrow();
console.error('測試中發現除以 0 的情況已正確處理');
});
總結
console.log與console.error是 除錯的第一線工具,善加利用能大幅提升開發效率。- 透過 佔位符、樣式、分組、表格化 等技巧,我們可以把訊息變得更有條理、更易讀。
- 注意 訊息等級的區分、避免洩漏機密、在上線前清除不必要的除錯輸出,才能保持程式的安全與效能。
- 結合 Lint、CI 與 環境條件,讓除錯流程自動化、標準化,進一步降低人為疏失。
掌握這些概念後,你將能在開發過程中 快速定位錯誤、洞悉執行流程,為後續的功能擴充與維護奠定堅實基礎。祝你在 JavaScript 的世界裡除錯無礙、開發順利!