JAVASCRIPT • DEBUGGING AND TESTING

Browser DevTools Debugger — Use browser devtools debugger conceptually (breakpoints, step, watch) (intro)

Learn to pause, inspect, and step through your JavaScript code like a detective solving a mystery.

Historical Context & Motivation

In the early days of programming, finding errors in code was incredibly tedious. Programmers would insert print statements throughout their code to display variable values, then sift through mountains of output text to locate the problem. As programs grew more complex, this approach became painfully slow and unreliable. Developers needed a smarter way to peek inside their running code—and that need gave birth to the debugger.

The word "bug" in computing traces back to 1947, when engineer Grace Hopper famously found an actual moth jammed inside a relay of the Harvard Mark II computer. While software errors had been called bugs before, this moment cemented the term in programmer culture. Debugging—the process of finding and removing those bugs—became a core discipline of software engineering.

1947
The First Literal Bug
Grace Hopper's team discovers a moth in the Mark II relay, popularizing the term "bug" for computer errors.
2006
Firebug Launches
The Firebug extension for Firefox becomes the first widely-used browser-based debugger, letting web developers inspect HTML, CSS, and JavaScript in real time.
2008
Chrome DevTools Arrives
Google Chrome ships with built-in developer tools, including a JavaScript debugger with breakpoints, stepping controls, and variable watching.
2015
Modern DevTools Ecosystem
All major browsers—Chrome, Firefox, Edge, Safari—offer robust built-in debuggers. DevTools become a standard skill for every web developer.

Today, every modern browser ships with powerful Developer Tools (DevTools) that let you pause your code mid-execution, examine exactly what each variable holds, and step through your logic line by line. This lesson introduces three essential debugging concepts: breakpoints, stepping, and watch expressions. How do these tools help you find bugs faster than sprinkling console.log() everywhere?

Core Principles & Definitions

Before diving into the debugger itself, you need to understand three foundational ideas that make debugging work. Think of the debugger as a remote control for your code—it gives you the power to pause, rewind, and slow-motion through every line of JavaScript your browser runs.

1

Breakpoints

A breakpoint is a marker you place on a specific line of code. When the browser reaches that line, it freezes execution so you can inspect everything at that exact moment.
2

Stepping

Once paused, stepping lets you advance your code one line at a time. You can step over a function call, step into it to see its internal logic, or step out to return to the caller.
3

Watch Expressions

A watch expression is a variable or expression you tell the debugger to monitor. Its value updates live as you step through your code, so you can track exactly when something goes wrong.
4

Call Stack

The call stack shows you the chain of function calls that led to the current line. It answers the question: "How did the program get here?"
5

Scope Panel

The scope panel displays all variables currently accessible at the paused line—local variables, closure variables, and global variables—along with their current values.
✦ KEY TAKEAWAY
Think of a breakpoint like pausing a movie at a key scene. Once paused, you can examine every detail on the screen—who is in the frame, what they're holding, what the background looks like. Stepping is like advancing frame by frame, and a watch expression is like tracking one specific character across every scene. Together, these tools let you understand exactly what your code does at every moment.

Visual Explanation — The DevTools Debugger Layout

The diagram below shows a simplified view of what you see when you open the Sources panel in Chrome DevTools (or the equivalent Debugger tab in Firefox). The interface is divided into three main regions: the file navigator on the left, the code editor in the center, and the debugging panels on the right.

The Sources panel layout: the file navigator (left) lets you select source files; the code editor (center) shows your JavaScript with a breakpoint marker on line 4; the right side panels display watch expressions, call stack, and scope information.

In the code editor, notice the cyan dot next to line 4. That is a breakpoint. When the browser reaches that line, it freezes. The highlighted row shows exactly where execution is paused. On the right, the Watch panel reveals live values for total, i, and items[i].price. Below that, the Call Stack tells you the current function (calculateTotal) was called by checkout, which was called from the top-level anonymous script. The Scope panel shows all variables accessible at this exact pause point.

How It Works — The Debugging Workflow

Debugging with DevTools follows a repeatable workflow. Rather than guessing where a bug might be, you form a hypothesis, set breakpoints near the suspicious code, and then let the evidence guide you. Here is the step-by-step mechanism of how the debugger operates.

Opening the Debugger

In most browsers, you press F12 (or Ctrl + Shift + I on Windows, Cmd + Option + I on Mac) to open DevTools. Then navigate to the Sources tab (Chrome/Edge) or the Debugger tab (Firefox). This is where all the debugging magic happens.

Setting a Breakpoint

Click on the line number in the code editor where you want the code to pause. A colored marker appears—this is your breakpoint. You can set as many breakpoints as you like. When JavaScript execution reaches a breakpointed line, the engine stops before that line runs. This means the variables show their values from just before that statement executes.

Stepping Through Code

Once paused at a breakpoint, you have four stepping options. Step Over executes the current line and moves to the next one; if the line contains a function call, it runs the entire function without pausing inside it. Step Into enters the function being called so you can see its internal logic line by line. Step Out finishes the current function and pauses at the line that called it. Finally, Resume continues normal execution until the next breakpoint or the end of the script.

Using Watch Expressions

In the Watch panel, click the "+" button and type any JavaScript expression—a variable name like total, or something more complex like items.length > 5. The debugger evaluates this expression at every pause and displays the current result. This is incredibly useful for tracking a value that changes across iterations of a loop.

💡 Pro Tip: The debugger Statement
You can also add the keyword debugger; directly into your JavaScript source code. When the browser hits this line (and DevTools is open), it pauses execution automatically—no need to click on line numbers. Just remember to remove the debugger; statement before deploying your code!

Detailed Breakdown — Stepping Actions Compared

The four stepping actions can feel confusing at first because they all move execution forward—but each one moves it in a different way. The diagram below illustrates what happens to the execution pointer when you use each stepping action while paused inside a function.

This diagram shows code paused at line 2 in main(). Step Over skips to line 3; Step Into enters double(); Step Out (if already inside double()) finishes it and returns to the caller.
Summary of the four stepping actions and their keyboard shortcuts in Chrome DevTools.
ActionKeyboard Shortcut (Chrome)What It Does
ResumeF8Continues running the script until the next breakpoint or end of program.
Step OverF10Executes the current line and pauses at the next one. Does not enter function calls.
Step IntoF11If the current line calls a function, enters that function and pauses at its first line.
Step OutShift + F11Finishes executing the current function and pauses at the line that called it.

Worked Example — Debugging a Buggy Loop

Imagine you have written a function that is supposed to calculate the average of an array of numbers, but it keeps returning NaN (Not a Number). Let's walk through how you would use the debugger to find the problem.

Here is the buggy code:

🐛 Buggy Code
function average(numbers) { let sum = 0; for (let i = 0; i <= numbers.length; i++) { sum += numbers[i]; } return sum / numbers.length; } — Calling average([10, 20, 30]) returns NaN instead of 20.
Debugging Step by Step
1
Step 1 — Set a BreakpointOpen DevTools (F12), go to the Sources tab, find your script file, and click on the line number for sum += numbers[i]; to set a breakpoint inside the loop. Now refresh the page or trigger the function.
Breakpoint set on the line inside the loop body.
2
Step 2 — Add Watch ExpressionsIn the Watch panel, add three expressions: i, numbers[i], and sum. These will update every time you step through the loop.
Watch panel now tracks three key expressions.
3
Step 3 — Step Over Through IterationsPress F10 (Step Over) repeatedly and observe the Watch panel. On the first pause: i = 0, numbers[0] = 10, sum = 0. After stepping: sum = 10. Continue stepping: i = 1, numbers[1] = 20, sum = 30. Next: i = 2, numbers[2] = 30, sum = 60. So far so good.
After three iterations: sum = 60 — correct so far!
4
Step 4 — Spot the BugStep one more time. Now i = 3, but numbers[3] shows undefined in the Watch panel! The array only has indices 0, 1, and 2. Adding undefined to 60 produces NaN. The loop condition uses <= instead of <, causing an off-by-one error.
Bug found! Change i <= numbers.length to i < numbers.length.
5
Step 5 — Verify the FixAfter fixing the condition, remove the breakpoint (click the dot again to toggle it off), press F8 to resume, and test the function. Now average([10, 20, 30]) returns 20 as expected.
Function returns 20 — bug fixed!

Debugger vs. console.log — Strengths & Limitations

Many beginners rely on console.log() to debug their code—and there's nothing wrong with that as a quick check. However, the DevTools debugger offers much more power. Let's compare these two debugging approaches.

Comparison of console.log() and the DevTools debugger for debugging JavaScript.
Featureconsole.log()DevTools Debugger
Setup effortLow — just add a line of codeLow — click a line number
Code changes requiredYes — must edit and re-run codeNo — breakpoints are external
Inspecting multiple variablesNeed a separate log for eachScope panel shows all at once
Stepping through logicNot possibleFull line-by-line control
Viewing call stackOnly with console.trace()Always visible when paused
Best forQuick one-off checksComplex bugs, logic errors, loops
✦ KEY TAKEAWAY
Using console.log() to debug is like trying to understand a car engine by listening to the sounds it makes—you can learn something, but it's limited. The DevTools debugger is like opening the hood and examining every part while the engine is frozen mid-stroke. Both have their place, but serious debugging calls for the real tool.

Connection to Advanced Debugging Techniques

The breakpoints, stepping, and watch expressions you have learned are the foundation of debugging—but DevTools offers much more as you advance. Understanding these basics prepares you for powerful techniques that professional developers use daily.

How basic debugging concepts connect to advanced DevTools techniques.
Basic Concept (This Lesson)Advanced Technique
Line breakpoint — pauses on a specific lineConditional breakpoint — only pauses when a condition is true (e.g., i === 50)
Watch a single variableLogpoints — log a message at a line without pausing, combining watch + console.log
Step through synchronous codeAsync debugging — step through Promises, async/await, and event listeners
Debug one file at a timeSource maps — debug minified or transpiled code by mapping it back to your original source
Manual breakpoint placementEvent listener breakpoints — pause whenever a specific DOM event (click, keydown, etc.) fires

As you build more complex web applications—especially ones with asynchronous operations like fetching data from APIs or handling user interactions—these advanced tools become essential. For now, mastering the basics of breakpoints, stepping, and watch expressions gives you a solid foundation that every future technique builds upon.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Explain in your own words what happens when the browser's JavaScript engine encounters a breakpoint. Why does execution pause before the breakpointed line runs, rather than after?
PROBLEM 2 — BASIC
You are paused at a breakpoint on this line: let result = multiply(a, b);. Describe what happens when you press each of these buttons: (a) Step Over, (b) Step Into, (c) Resume.
PROBLEM 3 — INTERMEDIATE
Consider this code: function greet(names) { for (let i = 0; i < names.length; i++) { let msg = 'Hello, ' + names[i]; console.log(msg); } } You set a breakpoint on the let msg = ... line and add a watch expression for names[i]. If names = ['Alice', 'Bob', 'Carol'], what values will the watch expression show each time the breakpoint is hit? How many times total will the breakpoint trigger?
PROBLEM 4 — APPLIED
You are building a to-do list app and the 'delete task' button is not working. When you click it, nothing happens—no errors in the console. Describe a debugging strategy using breakpoints, stepping, and watch expressions to isolate the problem. Be specific about where you would set breakpoints and what you would watch.
PROBLEM 5 — CRITICAL THINKING
A classmate argues: "I'll never need the debugger—I can find any bug with console.log()." Write a response that (a) acknowledges when console.log() is appropriate, (b) describes a specific scenario where the debugger is clearly superior, and (c) explains how using the debugger can actually help you become a better programmer, not just fix bugs faster.

Lesson Summary

The Browser DevTools Debugger transforms how you find and fix bugs in JavaScript. Instead of guessing with console.log(), you set breakpoints to pause execution at critical lines, use stepping controls (Step Over, Step Into, Step Out, Resume) to move through your code one line at a time, and create watch expressions to monitor specific variables and expressions as they change. The call stack shows you how your program reached the current line, while the scope panel reveals every variable accessible at the pause point.

To open the debugger, press F12 and navigate to the Sources tab (Chrome) or Debugger tab (Firefox). These foundational skills—setting breakpoints, stepping through logic, and watching values—are the building blocks for all advanced debugging techniques, including conditional breakpoints, async debugging, and source maps. Master these basics, and you will debug with confidence.

Varsity Tutors • JavaScript • Browser DevTools Debugger — Use browser devtools debugger conceptually (breakpoints, step, watch) (intro)