Skip to Content
Course content

117: Debugging with Breakpoints and Watch Expressions

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're a film director on a high-budget movie set. You're filming a complex action sequence, but something looks "off" in the playback. You can't just watch the whole scene at normal speed and hope to spot the mistake—it's too fast. Instead, you shout "Cut!" and freeze the action. You walk onto the set, move the actors an inch to the left, check if the prop gun is actually loaded with blanks, and then tell everyone to resume from exactly that frame.

Debugging with breakpoints is exactly that "Cut!" moment for your code. Instead of letting your program run from start to finish and guessing what happened based on the final output, you're freezing time. The "checking the props" part is where Watch Expressions come in—it's like having a magnifying glass pointed at one specific actor, so you don't have to scan the whole set to see if they're blinking at the wrong time.

Stopping Time in Your Code

Most of us start by peppering our code with console.log(). I did it for years. But honestly? It's a mess. You end up with a console full of noise, and you have to keep adding and removing logs just to track a single variable. Breakpoints are a cleaner way to do this.

Let's look at a real scenario. Say you're building a shopping cart, and for some reason, the final total is coming back as NaN. You've got a loop calculating prices, and somewhere, something is breaking.

function calculateOrderTotal(cart, taxRate) {
  let subtotal = 0;
  
  for (let i = 0; i < cart.length; i++) {
    const item = cart[i];
    // Imagine a bug here: one item is missing a price property
    subtotal += item.price * item.quantity;
  }

  const tax = subtotal * taxRate;
  return subtotal + tax;
}

const myCart = [
  { name: "Mechanical Keyboard", price: 150, quantity: 1 },
  { name: "USB-C Cable", price: 20, quantity: 2 },
  { name: "Desk Mat", quantity: 1 } // Oops, price is missing!
];

console.log(calculateOrderTotal(myCart, 0.08));

If you set a breakpoint on the line subtotal += item.price * item.quantity;, the browser will pause execution right there. You can then hover your mouse over item to see exactly what's inside it for that specific iteration of the loop. On the third pass, you'd see price: undefined, and you'd immediately know why the math is failing.

Keeping an Eye on the Suspects

Breakpoints are great for stopping, but Watch Expressions are for monitoring. When you're in the browser's Sources tab, there's a "Watch" pane. Instead of hovering over variables or digging through the entire "Scope" list, you can explicitly tell the debugger: "I don't care about anything else; just keep showing me the value of subtotal."

I find this incredibly useful when you're stepping through a loop. As you click the "Step Over" button to move to the next line, you can watch the subtotal value change in real-time. The moment it flips from a number to NaN, you've found your culprit. It transforms the process from "guessing where the bug is" to "watching the bug happen."

Navigating the Pause

Once you've hit a breakpoint, you have a few steering wheels at your disposal. You'll see a few icons in the debugger panel that I use every single day:

  • Step Over: This moves you to the next line. If the current line is a function call, it just runs the function and moves to the next line in the current file. It's the "just get me to the next line" button.
  • Step Into: This is for when you see a function call and think, "Wait, the bug might be inside that function." It dives deep into the function's definition.
  • Step Out: If you've stepped into a function and realized everything is fine there, this jumps you back out to the caller.

It takes a bit of practice to stop relying on the console, but once you get the hang of the debugger, you'll feel like you have superpowers. You're no longer reading a post-mortem report of what your code did; you're performing a live autopsy.




📋 Practical Task

Fixing the Broken Inventory Ledger

You've been handed a piece of code for an inventory system that is supposed to calculate the total value of a warehouse. However, the final result is incorrect, and the developer who wrote it left no logs behind. Your goal is to use breakpoints and watch expressions to find the logic error.

The Setup:

const inventory = [
  { item: "Laptop", stock: 10, valuePerUnit: 1000 },
  { item: "Mouse", stock: 50, valuePerUnit: 25 },
  { item: "Monitor", stock: 20, valuePerUnit: 200 },
  { item: "HDMI Cable", stock: 100, valuePerUnit: "15" }, // Note the type here
  { item: "Webcam", stock: 15, valuePerUnit: 80 }
];

function calculateWarehouseValue(items) {
  let totalValue = 0;
  for (let i = 0; i < items.length; i++) {
    const product = items[i];
    // BUG: The calculation here is causing weird string concatenation 
    // or incorrect math due to the data types in the inventory array.
    totalValue += product.stock + product.valuePerUnit; 
  }
  return totalValue;
}

console.log("Total Warehouse Value: " + calculateWarehouseValue(inventory));

Your Task:

  1. Copy this code into a browser's developer console or a JS file linked to an HTML page.
  2. Open the Sources tab in your browser's DevTools.
  3. Set a breakpoint inside the for loop.
  4. Add totalValue to your Watch Expressions list.
  5. Step through the loop iteration by iteration. Observe exactly which item causes totalValue to stop being a number and start becoming a string (or producing an incorrect sum).
  6. Fix the logic error in the calculateWarehouseValue function so that it correctly multiplies stock by value and handles the string "15" correctly.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.