By WebNest Studio Engineering Team
JavaScript Tutorial
Debugging JavaScript
Writing correct code the first time is rare — real development is a cycle of writing, running, observing what actually happened, and correcting course. Debugging is the disciplined version of that cycle, and JavaScript developers have two main toolsets for it: the console object for quick, low-friction inspection, and the browser's DevTools for deeper, interactive investigation.
Learning to debug efficiently — rather than sprinkling console.log everywhere and guessing — is one of the highest-leverage skills a JavaScript developer can build.
Why it matters
Developers spend far more time finding out why code misbehaves than writing it. Guessing and scattering console.log everywhere works slowly; a breakpoint that pauses the program and shows every variable works fast. Debugging methodically is one of the clearest differences between a beginner and an experienced developer.
Console Methods Beyond console.log
The console object offers several methods purpose-built for different kinds of output, and using the right one makes logs far easier to scan.
console.warn()— logs with a yellow warning style, for non-fatal issues worth noticing.console.error()— logs with a red error style and includes a stack trace, for actual failures.console.table(data)— renders an array of objects as a readable table, ideal for inspecting lists of records at a glance.console.group()/console.groupEnd()— visually nests related log lines so they can be collapsed together.
Breakpoints and Stepping Through Code
A breakpoint pauses code execution at a specific line, letting you inspect variables at that exact moment rather than guessing from logs after the fact. You can set a breakpoint by clicking a line number in the browser DevTools' Sources panel, or directly in code with the debugger; statement, which pauses execution automatically whenever DevTools is open. Once paused, you can step over, into, or out of function calls, and watch how variable values change line by line.
Browser DevTools Basics
Every major browser ships built-in developer tools (opened with F12 or right-click → Inspect). The Console panel runs JavaScript live against the current page and shows log output. The Sources panel shows your actual script files, lets you set breakpoints, and shows the call stack and local variables when paused. The Network panel shows every request the page makes, including status codes, timing, and response bodies — essential for debugging fetch calls and APIs. The Elements panel shows the live DOM tree and lets you inspect or edit it directly.
Examples
Using console.table, console.warn, and console.group for clearer output
const users = [
{ id: 1, name: 'Asha', age: 28 },
{ id: 2, name: 'Rahul', age: 31 },
];
console.group('User Report');
console.table(users);
users.forEach((user) => {
if (user.age < 18) {
console.warn(`${user.name} is a minor`);
}
});
console.groupEnd();
User Report
┌─────────┬────┬───────┬─────┐
│ (index) │ id │ name │ age │
├─────────┼────┼───────┼─────┤
│ 0 │ 1 │'Asha' │ 28 │
│ 1 │ 2 │'Rahul'│ 31 │
└─────────┴────┴───────┴─────┘
(no warnings logged, since both users are adults)
Pausing execution with the debugger statement to inspect state
function calculateTotal(cart) {
let total = 0;
for (const item of cart) {
debugger; // execution pauses here whenever DevTools is open
total += item.price * item.quantity;
}
return total;
}
const total = calculateTotal([
{ price: 10, quantity: 2 },
{ price: 5, quantity: 3 },
]);
console.log(total);
// With DevTools closed, "debugger" is simply ignored and the
// function runs straight through.
35
Common Mistakes
- Relying only on
console.logfor everything, missing how much fasterconsole.tableor a real breakpoint can make inspecting arrays of objects or complex state. - Leaving
debugger;statements or strayconsole.logcalls committed in production code, which can leak information or hurt performance. - Not checking the Network panel when a
fetch()call "does nothing" — the request may be failing, being blocked by CORS, or returning an error status that silent code isn't surfacing. - Reading a stack trace top-to-bottom instead of starting from the top (most recent call) to trace back to where the error actually originated.
Exercise
average should return 20 for the numbers 10, 20 and 30, but it prints NaN. Find the bug by logging the value of total on each pass, or by pausing with debugger, and fix it.
Expected output: 20
function average(numbers) {
let total = 0;
for (let i = 0; i <= numbers.length; i++) {
total += numbers[i];
}
return total / numbers.length;
}
console.log(average([10, 20, 30]));
Show hints
- On the last pass,
numbers[i]isundefined, and addingundefinedto a number givesNaN. - The last valid index is
numbers.length - 1, so the condition should use<.
Show solution
function average(numbers) {
let total = 0;
for (let i = 0; i < numbers.length; i++) {
total += numbers[i];
}
return total / numbers.length;
}
console.log(average([10, 20, 30]));
Quick quiz
1. What does the debugger statement do when DevTools is open?
- A. Prints the stack trace
- B. Deletes all breakpoints
- C. Restarts the script
- D. Pauses execution at that line, like a breakpoint
Show answer
D. With DevTools closed it has no effect.
2. Which console method displays an array of objects as a table?
- A. console.table
- B. console.grid
- C. console.list
- D. console.dir
Show answer
A. It is much easier to scan than nested log output.
3. While paused at a breakpoint, what does "Step over" do?
- A. Skips the rest of the function
- B. Runs the current line and pauses at the next one, without entering functions it calls
- C. Removes the breakpoint
- D. Restarts the page
Show answer
B. "Step into" enters the called function, and "Step out" finishes the current one.
Interview questions
How do you debug a JavaScript problem?
Show answer
Reproduce it reliably and read the error message and stack trace in the Console. Form a guess about the cause and test it: set a breakpoint in the Sources panel just before the failure, step through the code, and compare the actual values of variables with the ones expected. Check the Network panel if data from a server is involved. Narrow the problem down until the first wrong value is found, then fix the cause.
When would you use a breakpoint instead of console.log?
Show answer
console.log is quick for confirming a single value. A breakpoint is better when the cause is unknown: it pauses the program and exposes every variable in scope and the whole call stack, lets you step line by line, and needs no code change or reload for each new question. Conditional breakpoints pause only when an expression is true, which helps inside loops.
Key Points to Remember
- Use
console.warn,console.error,console.table, andconsole.groupfor clearer, more purposeful logging than plainconsole.log. - Breakpoints (set in DevTools or via the
debugger;statement) pause execution so you can inspect real state, which is often faster than guessing from logs. - The Sources panel debugs code, the Network panel debugs requests, and the Elements panel debugs the live DOM.
- Remove
debugger;statements and diagnostic logs before shipping to production.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Shows a live preview of your HTML, CSS and JavaScript. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering