Debugging

Console, breakpoints, devtools

Debugging JavaScript

Debugging is the process of finding and fixing errors in your code. Modern browsers have powerful developer tools that make debugging easier.

Console Methods

// Basic logging
console.log('Hello');           // General output
console.info('Info message');   // Informational
console.warn('Warning!');       // Warning (yellow)
console.error('Error!');        // Error (red)

// Log multiple values
console.log('User:', { name: 'Alice', age: 30 });

// Template literals for formatting
const user = 'Bob';
console.log(`Welcome, ${user}!`);

// Log with label (cleaner output)
console.log({ user, count: 5, active: true });

// Table view (great for arrays of objects)
const users = [
  { name: 'Alice', age: 30 },
  { name: 'Bob', age: 25 }
];
console.table(users);

Advanced Console

// Group related logs
console.group('User Details');
console.log('Name: Alice');
console.log('Age: 30');
console.groupEnd();

// Measure execution time
console.time('Operation');
// ... some code ...
console.timeEnd('Operation');  // Logs: "Operation: 123.45ms"

// Count function calls
function myFunction() {
  console.count('myFunction called');
}
myFunction();  // "myFunction called: 1"
myFunction();  // "myFunction called: 2"

// Stack trace
console.trace('Trace point');

// Conditional logging
const x = 5;
console.assert(x > 10, 'x should be greater than 10');

Using Breakpoints

Setting Breakpoints in DevTools

  1. Open DevTools (F12 or Cmd+Option+I)
  2. Go to "Sources" tab
  3. Find your file in the file tree
  4. Click on a line number to add a breakpoint
  5. Reload the page or trigger the code
  6. Execution will pause at the breakpoint
// Debugger statement (programmatic breakpoint)
function calculate(a, b) {
  debugger;  // Execution pauses here if DevTools is open
  return a + b;
}

Step Through Code

When paused at a breakpoint, you can:

▶️ Resume (F8)

Continue execution until next breakpoint

↘️ Step Over (F10)

Execute current line and move to next

⤵️ Step Into (F11)

Go inside function call

⤴️ Step Out (Shift+F11)

Finish current function and return

Inspecting Variables

function processUser(user) {
  debugger;  // Pause here
  
  // When paused, you can:
  // 1. Hover over variables to see values
  // 2. Type in console: user, user.name, etc.
  // 3. Check "Scope" panel in DevTools
  // 4. Add watches for expressions
  
  const name = user.name.toUpperCase();
  return name;
}

Common Errors & Solutions

TypeError: Cannot read property 'x' of undefined

// Problem
const user = null;
console.log(user.name);  // Error!

// Solutions
if (user) {
  console.log(user.name);
}

// Or use optional chaining
console.log(user?.name);  // undefined (no error)

ReferenceError: variable is not defined

// Problem
console.log(myVar);  // Error! Variable doesn't exist

// Solution: Check spelling and declaration
const myVar = 'Hello';
console.log(myVar);  // "Hello"

SyntaxError: Unexpected token

// Problem: Missing closing bracket/parenthesis
function test() {
  console.log('hi');
// Missing closing brace!

// Solution: Check all brackets are closed
function test() {
  console.log('hi');
}  // Added closing brace

Network Debugging

// Check Network tab in DevTools to debug:

// 1. API request status
fetch('https://api.example.com/users')
  .then(response => {
    console.log('Status:', response.status);  // 200, 404, 500, etc.
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .catch(error => console.error('Fetch error:', error));

// 2. Inspect request/response headers
// 3. Check payload data
// 4. View response time

Performance Profiling

// Measure function performance
function slowFunction() {
  console.time('slowFunction');
  
  // Your code here
  for (let i = 0; i < 1000000; i++) {
    // ...
  }
  
  console.timeEnd('slowFunction');  // "slowFunction: 45.2ms"
}

// Use Performance tab in DevTools:
// 1. Click record button
// 2. Perform actions
// 3. Stop recording
// 4. Analyze flame graph for bottlenecks

Memory Leaks

// Common memory leak: Event listeners not removed
const button = document.querySelector('#btn');
const handler = () => console.log('Clicked');

// Add listener
button.addEventListener('click', handler);

// Later, if you remove button from DOM:
button.remove();

// But listener still exists in memory!
// Fix: Remove listener before removing element
button.removeEventListener('click', handler);
button.remove();

// Use Memory tab in DevTools to detect leaks:
// 1. Take heap snapshot
// 2. Perform actions
// 3. Take another snapshot
// 4. Compare to see what's growing

🛠️ DevTools Shortcuts

  • F12 / Cmd+Opt+I: Open DevTools
  • Cmd+Opt+J: Open Console directly
  • Cmd+P: Quick file search
  • Cmd+Shift+P: Command palette
  • Cmd+F: Search in current file

✓ Debugging Best Practices

  • • Use console.log() strategically, not everywhere
  • • Remove debug logs before committing code
  • • Use breakpoints over console.log for complex debugging
  • • Check Network tab for API issues
  • • Read error messages carefully—they tell you what's wrong!
  • • Use descriptive variable names to reduce confusion
  • • Test small pieces of code in isolation