JavaScript Notes
Master JavaScript debugging: console.log, console.table, console.trace, DevTools breakpoints, debugger statement, error stack traces, and debugging async code.
Debugging is the process of finding and fixing bugs — unexpected behavior in your code. JavaScript has powerful built-in tools for debugging: the console API, the debugger statement, browser DevTools, and Node.js inspect mode.
Every developer spends a significant portion of their time debugging — learning these tools makes you dramatically faster.
📊 Debugging Process Flow
Bug reported / Error observed
│
▼
Read the error message & stack trace
│
▼
Reproduce the bug reliably
│
▼
Narrow down the location
(console.log / breakpoints)
│
▼
Inspect variables & state
│
▼
Identify root cause
│
▼
Fix & verify fix works
│
▼
Test edge cases💻 Example 1 — The console API: Complete Reference
Hello, Debug!
Multiple: 1 values: true [ 1, 2, 3 ]
Something went wrong: oops
This feature is deprecated
Server started on port 3000
┌─────────┬───────┬───────┬───────┐
│ (index) │ name │ grade │ score │
├─────────┼───────┼───────┼───────┤
│ 0 │ 'Riya'│ 'A' │ 95 │
│ 1 │ 'Aman'│ 'B' │ 82 │
│ 2 │'Priya'│ 'A' │ 91 │
└─────────┴───────┴───────┴───────┘
{ a: 1, b: { c: 2, d: [ 3, 4 ] } }💻 Example 2 — Timing and Grouping
sort-benchmark: 12.847ms
User Authentication
Checking credentials...
Valid: true
Token
Generated: JWT-abc123
Expires: 1h
processItem called: 1
processItem called: 2
processItem called: 3
processItem called: 4💻 Example 3 — console.trace() and console.assert()
// console.trace — show call stack at this point
function c() { console.trace("Trace from c()"); }
function b() { c(); }
function a() { b(); }
a();
console.log("---");
// console.assert — only logs if condition is FALSE
const score = 75;
console.assert(score >= 90, "Score is below A grade:", score);
console.assert(score >= 60, "Score is below passing:", score); // won't log — passes
console.assert(score < 0, "Score is negative:", score); // won't log — falseTrace from c():
at c (script.js:2)
at b (script.js:3)
at a (script.js:4)
at script.js:5
---
Assertion failed: Score is below A grade: 75💻 Example 4 — The debugger Statement
The debugger statement pauses execution in DevTools (or Node.js --inspect mode) — like setting a breakpoint from code.
function calculateDiscount(price, percent) {
debugger; // ← pauses here in DevTools! Inspect price and percent
const discount = price * (percent / 100);
const finalPrice = price - discount;
return finalPrice;
}
const result = calculateDiscount(1000, 20);
console.log("Final price:", result);Final price: 800
In browser DevTools: open the Sources panel, refresh the page — execution pauses at debugger. You can inspect variables, step through line by line, and watch expressions.💻 Example 5 — Reading Error Stack Traces
function fetchData(url) {
if (!url) throw new Error("URL is required");
return `data from ${url}`;
}
function loadUser(id) {
const url = id > 0 ? `/api/user/${id}` : null;
return fetchData(url); // throws if id <= 0
}
function initApp() {
const user = loadUser(-1); // bug: negative id
console.log(user);
}
try {
initApp();
} catch (error) {
console.log("Error:", error.message);
console.log("\nStack trace:");
console.log(error.stack);
}Error: URL is required
Stack trace:
Error: URL is required
at fetchData (debug.js:2) ← Error originated here
at loadUser (debug.js:7) ← called from here
at initApp (debug.js:12) ← called from here
at Object.<anonymous> (debug.js:16)How to read a stack trace: Read from top to bottom. The top line is where the error was thrown. Each line below shows which function called the one above it. The bug is usually at the top — follow the chain to find where the wrong data came from.
💻 Example 6 — Debugging Async Code
[renderProfile] Starting...
[renderProfile] Starting...
[fetchUser] Called with id=1
[fetchUser] Called with id=-5
[fetchUser] Returning: { id: 1, name: 'Riya' }
[renderProfile] Rendering: Riya
[renderProfile] Failed: Invalid id: -5📋 Debugging Tools Quick Reference
| Tool | Use When |
|---|---|
console.log(value) | Quick value inspection |
console.table(array) | Inspect arrays of objects visually |
console.error(msg) | Mark errors in output |
console.trace() | See the call stack at a point |
console.time/timeEnd | Measure performance |
console.group/groupEnd | Organize complex logs |
console.assert(cond, msg) | Log only when condition fails |
debugger | Pause in DevTools and inspect |
error.stack | Read the call chain in errors |
⚠️ Common Mistakes
❌ Mistake 1 — Logging Objects by Reference (Snapshot Problem)
const user = { name: "Riya", score: 0 };
console.log(user); // Shows current state when DevTools reads it — may differ from when logged!
console.log({ ...user }); // BETTER: log a snapshot (spread copies the state now)
user.score = 100;❌ Mistake 2 — Leaving debugger in Production Code
// NEVER ship this to production
function processOrder() {
debugger; // ← blocks execution for all users if DevTools is open!
// ...
}❌ Mistake 3 — Not Reading the Stack Trace
// Most beginners see an error and immediately guess the cause.
// Always READ the stack trace first — it tells you exactly where the error is.
// Line 1 of the stack = where the error was thrown
// Follow each line up to find where the bad data came from❌ Mistake 4 — Using console.log Instead of console.error for Errors
// BAD — errors look like normal output
console.log("Error:", err);
// GOOD — errors are visually distinct and filtered separately
console.error("Error:", err);🎯 Key Takeaways
- Read the error message first — it usually tells you exactly what went wrong
- Stack trace shows the exact function chain — follow it from top to bottom
console.table()is excellent for debugging arrays of objectsconsole.time/timeEndidentifies performance bottlenecksdebuggerpauses execution in DevTools — far more powerful than console.log for complex bugs- Always remove
debuggerstatements before committing or deploying code - For async bugs: add
console.logat entry and exit of each async function to trace the flow
❓ Interview Questions
Q1. What are the most useful console methods for debugging? > console.log() for general output, console.error() for errors (red), console.warn() for warnings (yellow), console.table() for arrays/objects, console.trace() for call stacks, console.time/timeEnd for performance measurement.
Q2. What is the debugger statement? > It's a JavaScript keyword that pauses execution when browser DevTools (or Node.js --inspect) is open. It acts like a programmatically placed breakpoint, letting you inspect variables, step through code line-by-line, and evaluate expressions in the console.
Q3. How do you read a JavaScript stack trace? > The first line is the error type and message. Each subsequent line shows a function name and file/line number. Read top to bottom — the top is where the error was thrown, and each line below is the caller of the one above. The bug's root cause is usually where bad data entered the chain.
Q4. How do you debug asynchronous JavaScript code? > Add descriptive console.log statements at the start and end of async functions with the function name and key values. Use debugger in async functions — DevTools pauses correctly. In Node.js, use --inspect flag and Chrome DevTools for async debugging. Check for missing await keywords first.
Q5. What is the difference between console.log(obj) and console.log({...obj})? > console.log(obj) logs a reference — if you expand the object in DevTools later, you see the current state (which may have changed after logging). console.log({...obj}) logs a shallow copy — a snapshot of the values at the moment of logging.
Q6. What does console.assert() do? > It logs a message only when the first argument is falsy. Unlike if + console.log, it's concise and clearly communicates "this should always be true." Useful for catching unexpected states during development without adding full error handling.
Q7. How do you measure the performance of a function? > Use console.time("label") before calling the function and console.timeEnd("label") after. The elapsed time in milliseconds is logged. For more precise measurements, use the performance.now() API.
Q8. What is a common mistake when debugging objects with console.log? > Logging an object reference — when you later expand it in browser DevTools, you see the object's current (mutated) state, not its state at the time of logging. Use console.log(JSON.stringify(obj)) or spread ({...obj}) to capture an immutable snapshot.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Debugging – console Methods, DevTools, Breakpoints & Error Stack Traces.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, error, handling, debugging
Related JavaScript Master Course Topics