Computer Programming 1 (JavaScript) • Debugging, Testing & Code Quality

Debugging Tools — I can use console logging or a debugger conceptually (breakpoints/step) to inspect state at my level.

Learn to find and fix bugs by inspecting your program's state with console.log and browser debugger tools.

A JavaScript data file with code brackets and a laptop.
Inside this lesson 10 sections 5 questions 5 figures

SECTION 1

Historical Context & Motivation

Every programmer, from beginners to seasoned professionals, encounters bugs — errors in code that cause unexpected behavior. The word "bug" has been used in engineering since the 1800s, but it became famous in computing when a moth was found stuck in a relay of the Harvard Mark II computer in 1947. Since those early days, developers have needed systematic ways to track down and fix these errors, which is exactly what debugging tools are designed to do.

In the earliest days of programming, debugging meant physically examining hardware or reading through printed output line by line. As software grew more complex, programmers realized they needed better tools to peer inside a running program. Two major approaches emerged: printing values to an output screen (what we now call console logging) and using interactive debuggers that let you pause execution and examine your program's state step by step.

1947 • The First Famous 'Bug'

Grace Hopper's team finds a moth in the Harvard Mark II relay, coining the term "debugging" for removing errors from a computer.

1960s • Print Statement Debugging

Programmers begin inserting print statements into code to display variable values during execution, the earliest form of console logging.

1980s • Interactive Debuggers Emerge

Tools like GDB (GNU Debugger) allow developers to set breakpoints and step through code one line at a time, inspecting memory and variables.

1995 • JavaScript Is Born

Brendan Eich creates JavaScript for Netscape Navigator. Early JS debugging is extremely limited, relying on alert() pop-ups to inspect values.

2006–Present • Modern Browser DevTools

Firebug (2006), Chrome DevTools (2008), and modern browser developer tools offer console.log, breakpoints, step-through debugging, and variable inspection built right into the browser.

Today, the question is not whether debugging tools exist — they are built into every modern browser. The real question is: how do you use these tools effectively to find and understand bugs in your own code? This lesson will teach you exactly that.

SECTION 2

Core Principles of Debugging

Debugging is fundamentally about answering one question: what is my program actually doing versus what I expected it to do? To answer that question, you need to inspect program state — the current values of all variables and the current position of execution — at different moments while your code runs. Every debugging technique boils down to this core idea.

1

Program State

The collection of all variable values, function call positions, and data structures at any given moment during execution. Debugging means inspecting this state to find where it differs from what you expected.
2

Console Logging

Using console.log() statements to print variable values and messages to the browser console. This is the simplest and most common debugging technique in JavaScript.
3

Breakpoints

Markers you place on specific lines of code that tell the debugger to pause execution when it reaches that line. While paused, you can examine every variable's current value.
4

Stepping Through Code

After pausing at a breakpoint, you can execute your code one line at a time using Step Over (next line), Step Into (enter a function), or Step Out (finish the current function). This reveals the exact order of execution.
5

Isolate, Hypothesize, Test

Effective debugging follows a scientific method: isolate where the bug might be, form a hypothesis about what's wrong, then use logging or breakpoints to test that hypothesis. Repeat until you find the cause.
✦

KEY TAKEAWAY

Think of debugging like being a detective at a crime scene. The "crime" is the bug. Console logging is like dusting for fingerprints — you sprinkle print statements around to gather clues. A debugger with breakpoints is like freezing time at the crime scene so you can walk through every room and examine every detail at your own pace. Both approaches help you find the culprit, but sometimes one is faster than the other.

SECTION 3

Visual Explanation — Console Logging Flow

The following diagram shows how console.log() works during program execution. When your JavaScript code runs, the engine processes each line in order. When it hits a console.log() call, it evaluates the expression inside the parentheses and prints the result to the browser console — without stopping the program. The code keeps running normally. This lets you see a "trail" of values as your program executes.

How console.log() Works During ExecutionYOUR CODElet score = 0;score = score + 10;console.log(score);score = score * 2;console.log(score);score = score - 5;console.log(score);1234567BROWSER CONSOLE OUTPUT▸ 10(score after +10)▸ 20(score after ×2)▸ 15(score after −5)KEY INSIGHTThe program never pauses.Values print in order as eachconsole.log() line is reached.You read the trail afterward.Arrows show which console.log() produced each output line
The left panel shows your JavaScript code with three console.log() calls highlighted in cyan. The right panel shows the browser console output. Each arrow connects a log statement to its printed result, allowing you to trace how the score variable changes over time.

Notice that the program runs all the way through without stopping. Console logging is a passive debugging technique — you add print statements before running your code, then read the output afterward to piece together what happened. It is fast to set up and works in any environment, but for complex bugs you may need something more interactive.

SECTION 4

How the Browser Debugger Works

While console logging prints values passively, a browser debugger gives you active control over your program's execution. Every modern browser — Chrome, Firefox, Safari, Edge — has built-in Developer Tools (often called DevTools) that include a Sources panel where you can set breakpoints, pause execution, and step through your code line by line.

Setting a Breakpoint

To set a breakpoint, you open DevTools (press F12 or Ctrl+Shift+I on Windows, Cmd+Option+I on Mac), navigate to the Sources tab, find your JavaScript file, and click on the line number where you want execution to pause. A colored marker appears on that line. The next time your code runs and reaches that line, the JavaScript engine freezes the entire program right there, before executing that line. You can then see the value of every variable that exists at that moment.

Stepping Controls

Once paused, the debugger gives you several buttons to control what happens next. These are the three most important stepping actions you need to understand.

1

Step Over (F10)

Executes the current line and moves to the next line in the same function. If the current line calls a function, it runs that entire function without pausing inside it. Use this when you trust the called function works correctly.
2

Step Into (F11)

If the current line calls a function, the debugger jumps inside that function and pauses at its first line. Use this when you suspect the bug is inside a function call and you want to examine it from the inside.
3

Step Out (Shift+F11)

Finishes executing the rest of the current function and pauses at the line right after the function was called. Use this when you've finished examining a function and want to return to the calling code.

The debugger Statement

JavaScript also provides a built-in keyword — debugger; — that you can write directly in your code. When the JavaScript engine encounters this keyword and DevTools is open, it pauses execution just like a breakpoint. This is useful when you want to quickly add a breakpoint without navigating through the DevTools interface. Just remember to remove debugger statements from your code before you ship it, since they will cause the browser to freeze if DevTools is open.

SECTION 5

Console Logging Techniques & the Scope Panel

While console.log() is the most common console method, JavaScript provides several other useful variants. Knowing which one to use in different situations makes your debugging output much easier to read.

MethodPurposeExample
console.log()General-purpose output for any valueconsole.log("score:", score)
console.warn()Prints a yellow warning messageconsole.warn("score is negative!")
console.error()Prints a red error messageconsole.error("Failed to load data")
console.table()Displays arrays/objects as a tableconsole.table(students)
console.log({name, age})Logs variable names with values using shorthand// Output: {name: 'Ada', age: 16}

Common console methods for JavaScript debugging

💡

Pro Tip: Label Your Logs

Always include a descriptive string before your variable, like console.log("score after bonus:", score). Without labels, a console full of numbers like 10, 20, 15 is almost useless because you won't remember which log printed which value.
Debugger Breakpoint: Paused Execution ViewSOURCES PANEL — Code1function calcGrade(pts, total) {2 let pct = pts / total * 100;3 let grade = getLetterGrade(pct);⏸ PAUSED4 return grade;5}6calcGrade(42, 50);▶Step ⤵Step →Step ⤴Resume Step Into Step Over Step OutSCOPE PANEL — Variable Values▾ Localpts: 42total: 50pct: 84grade: undefined(not yet assigned)WHAT YOU CAN SEE✓ pts and total were passed correctly✓ pct computed as 84 (42/50 × 100)✓ grade is undefined (line 3 hasn't run yet)STEPPING DECISION AT THIS POINTStep Over → skips into getLetterGrade, goes to line 4 | Step Into → jumps inside getLetterGrade to see what it doesThe red dot on line 3 is a breakpoint. The yellow highlight shows the currently paused line.
This diagram simulates what you see in Chrome DevTools when paused at a breakpoint. The left panel shows your code with a red dot (breakpoint) on line 3 and a yellow highlight showing where execution is paused. The right panel shows the Scope panel, which reveals every variable's current value. Notice that grade is still undefined because line 3 hasn't executed yet.

The Scope panel is one of the most powerful parts of the debugger. Instead of manually adding console.log() for every variable, you can see all variables at once — including ones you forgot to log. You can also hover over any variable name directly in the code panel to see its value in a tooltip. This is especially useful when dealing with objects and arrays, which can be expanded to see their contents.

SECTION 6

Worked Example — Finding a Bug with Debugging Tools

Let's walk through a realistic debugging scenario. A student has written a function to calculate the average of an array of test scores, but the function returns NaN (Not a Number) instead of the expected average. Here is the buggy code:

⚠

Buggy Code

function average(scores) { let sum; for (let i = 0; i <= scores.length; i++) { sum = sum + scores[i]; } return sum / scores.length; } console.log(average([80, 90, 100])); Expected output: 90. Actual output: NaN

Debugging with console.log()

  1. 1

    Step 1 — Add strategic log statements

    We don't know where the bug is, so we add log statements to inspect the key variables at critical points. We add console.log("sum before loop:", sum) before the loop, and console.log("i:", i, "scores[i]:", scores[i], "sum:", sum) inside the loop.
  2. 2

    Step 2 — Run the code and read the console output

    The console now shows: sum before loop: undefined i: 0 scores[i]: 80 sum: NaN i: 1 scores[i]: 90 sum: NaN i: 2 scores[i]: 100 sum: NaN i: 3 scores[i]: undefined sum: NaN
    Two bugs found! sum starts as undefined (not 0), and the loop runs one extra time (i = 3 when array length is 3).
  3. 3

    Step 3 — Identify Bug #1: sum is not initialized

    The line let sum; declares sum but doesn't assign a value, so it defaults to undefined. When you add a number to undefined, JavaScript returns NaN. The fix is to write let sum = 0;
    Fix: Change let sum; to let sum = 0;
  4. 4

    Step 4 — Identify Bug #2: off-by-one error in the loop

    The condition i <= scores.length should be i < scores.length. When i equals 3, scores[3] is undefined because the valid indices are 0, 1, and 2. This is called an off-by-one error, one of the most common bugs in programming.
    Fix: Change i <= scores.length to i < scores.length
  5. 5

    Step 5 — Verify the fix

    After applying both fixes, the corrected code is: function average(scores) { let sum = 0; for (let i = 0; i < scores.length; i++) { sum = sum + scores[i]; } return sum / scores.length; } Running average([80, 90, 100]) now returns 90, as expected. You can remove the console.log statements since the bug is fixed.
    Output: 90 ✓

SECTION 7

Console Logging vs. Debugger — When to Use Which

Both console logging and the debugger are essential tools, but they each have strengths and weaknesses. Experienced developers use both techniques together depending on the situation. The key is knowing which tool fits the problem you're facing.

Featureconsole.log()Browser Debugger
Speed to set upVery fast — just type a line of codeTakes a few clicks to open DevTools and set breakpoints
Amount of infoOnly shows what you explicitly logShows ALL variables in scope automatically
Execution controlNone — program runs to completionFull control — pause, step, resume
Best forQuick checks, logging over time, tracking event orderComplex logic, examining objects, understanding flow
Code changes neededYes — must add and later remove log statementsNo — breakpoints are set in the browser, not in your code
Risk of leaving inClutters console if forgottenNo risk — breakpoints disappear when DevTools closes

Comparing the two primary JavaScript debugging techniques

✦

KEY TAKEAWAY

Think of console.log() as taking photos during a road trip — you get snapshots at moments you chose in advance. Think of the debugger as having a dashcam with a pause button — you can freeze the trip at any moment and look around in every direction. For simple bugs, photos (logging) are often enough. For mysterious bugs, the dashcam (debugger) gives you a complete picture.

SECTION 8

Connection to Advanced Debugging Concepts

The console logging and breakpoint techniques you've learned in this lesson are foundational skills that scale into much more powerful tools as you advance. Professional developers build on these same concepts, using more sophisticated versions of the same ideas.

What You Know NowWhat Comes Next
console.log() to print valuesStructured logging frameworks that write logs to files with timestamps, severity levels, and automatic formatting
Setting breakpoints by clicking line numbersConditional breakpoints that only pause when a specific condition is true, like i === 50
Stepping through code one line at a timeWatch expressions that continuously evaluate a custom expression (like arr.length > 10) as you step
Reading the Scope panelCall stack inspection — viewing the chain of function calls that led to the current line, essential for understanding complex programs
Debugging in the browserIDE debuggers (like VS Code) that provide the same breakpoint and stepping features for Node.js, Python, Java, and other languages

How today's skills connect to advanced debugging techniques

The mental model is always the same: inspect state, form a hypothesis, test it. Whether you're using a simple console.log() in a browser or a full-featured debugger in a professional IDE, the thought process stays identical. Mastering that thought process now will serve you in every programming language and environment you encounter in the future.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

What is the fundamental difference between debugging with console.log() and debugging with breakpoints? Explain in terms of when you see the information and whether the program pauses.
Show answer
With console.log(), the program runs all the way through without pausing, and you read the printed output afterward — it's a passive approach. With breakpoints, the program pauses at the marked line, and you can examine all variable values right at that moment before deciding whether to continue. The debugger gives you real-time, interactive access to program state, while console logging only shows you what you explicitly chose to print in advance.

Question 2: BASIC CALCULATION

Consider this code: let x = 5; let y = x * 3; console.log("y is:", y); y = y + 2; console.log("y is:", y); What will be printed in the console? Write the exact two lines of output.
Show answer
The console will print: y is: 15 y is: 17 The first console.log() runs after y = x * 3 (which is 5 × 3 = 15). The second runs after y = y + 2 (which is 15 + 2 = 17). Each log statement captures the value of y at the moment that specific line executes.

Question 3: INTERMEDIATE

A student sets a breakpoint on line 3 of the following code and runs it. When the debugger pauses, what values will appear in the Scope panel for each variable? let name = "Alice"; // line 1 let greeting = "Hello " + name; // line 2 let upper = greeting.toUpperCase(); // line 3 console.log(upper); // line 4 Remember: the breakpoint pauses before executing the marked line.
Show answer
When paused at line 3, lines 1 and 2 have already executed but line 3 has not. The Scope panel will show: name = "Alice", greeting = "Hello Alice", and upper = undefined. The variable upper has been declared (due to hoisting) but not yet assigned, because the assignment on line 3 has not executed yet. If you press Step Over, line 3 will execute and upper will become "HELLO ALICE".

Question 4: APPLIED

You wrote a function that should double every number in an array, but the output is wrong: function doubleAll(arr) { let result = []; for (let i = 0; i < arr.length; i++) { result.push(arr[i] + arr[i]); } return result; } console.log(doubleAll(["3", "5", "7"])); // Expected: [6, 10, 14] // Actual: ["33", "55", "77"] Describe how you would use console.log() to diagnose this bug. What specific log statement would reveal the problem, and what would you see in the output?
Show answer
You could add console.log(typeof arr[i], arr[i]) inside the loop. This would print string 3, string 5, string 7, revealing that the array elements are strings, not numbers. In JavaScript, the + operator concatenates strings instead of adding them. The fix is to convert the strings to numbers first using Number(arr[i]) or to pass an array of actual numbers [3, 5, 7] instead of ["3", "5", "7"]. Using typeof in your log statement is a powerful technique for catching type-related bugs.

Question 5: CRITICAL THINKING

A classmate says: "I never use the debugger. I just put console.log() everywhere and that's enough." Another classmate says: "console.log is a waste of time — just use breakpoints for everything." Who is right? Write a paragraph arguing that both are partially right but that the best approach is to use both tools. Include at least one specific scenario where console.log is the better choice and one where the debugger is the better choice.
Show answer
Both classmates are partially right, but neither approach alone is optimal. Console.log is the better choice when you need to track how a value changes over many iterations of a loop — for example, if you want to see how a running total grows across 100 iterations, printing 100 values is faster than stepping through 100 times with a breakpoint. The debugger is the better choice when you need to inspect a complex object with many nested properties, because the Scope panel lets you expand and explore the entire object structure at the exact moment of the bug, whereas you'd need many log statements to print each property individually. Professional developers typically start with a few targeted console.log statements to narrow down which section of code contains the bug, then switch to the debugger with breakpoints to examine that specific section in detail. Using both tools together is the most efficient debugging strategy.

SUMMARY

Lesson Summary

Summary

Debugging is the process of finding and fixing errors by inspecting program state — the values of variables and the position of execution at any given moment. The two essential tools for JavaScript debugging are console.log(), which prints values to the browser console without pausing your program, and the browser debugger, which lets you set breakpoints to pause execution and use stepping controls (Step Over, Step Into, Step Out) to walk through code one line at a time.

Effective debugging follows a scientific method: isolate the suspicious area, hypothesize what's wrong, then use logging or breakpoints to test your hypothesis. Remember to always label your console.log() messages so you can tell which output came from which log statement. Use console.log for quick checks and tracking values over time, and use the debugger when you need to examine complex state or understand unfamiliar code flow. Both tools are complementary, and knowing when to reach for each one is the mark of an effective programmer.

Varsity Tutors • Computer Programming 1 (JavaScript) • Debugging Tools — I can use console logging or a debugger conceptually (breakpoints/step) to inspect state at my level.