5  Debugging JavaScript

learning goals
  • Understand how JavaScript handles errors and stops code execution at error points
  • Identify and fix common syntax errors including mismatched quotes, brackets, and braces
  • Recognize and resolve reference errors and type errors
  • Use systematic debugging strategies including console.log() and browser developer tools
  • Apply step-by-step debugging processes to isolate and fix problems
  • Prevent common bugs through good coding practices and testing approaches

Debugging is an essential skill for any programmer. When your code doesn’t work as expected, systematic debugging helps you identify and fix the problem quickly. As a beginner, you’ll encounter certain types of errors frequently. Learning to recognize and resolve them will make you a more confident programmer.

5.1 How JavaScript Handles Errors

Important: When JavaScript encounters an error, it stops executing your code at that exact point. This behavior is actually helpful for debugging because it tells you precisely where the problem occurred.

console.log("This line runs");
console.log("This line also runs");
let result = someUndefinedVariable + 5;  // Error occurs here
console.log("This line NEVER runs");     // Code stops at the error above
console.log("Neither does this line");

Console output:

This line runs
This line also runs
ReferenceError: someUndefinedVariable is not defined
    at script.js:3:14

Notice that the last two console.log() statements never execute because JavaScript stopped when it hit the error on line 3.

5.1.1 Using This to Your Advantage

You can use JavaScript’s “stop on error” behavior to narrow down where problems occur:

console.log("Step 1: Starting the program");

let numbers = [1, 2, 3];
console.log("Step 2: Created array");

let sum = 0;
console.log("Step 3: Initialized sum");

// If you see "Step 3" but not "Step 4" in the console,
// you know the error is in the next line
for (let i = 0; i <= numbers.length; i++) {  // Bug: should be < not <=
    console.log("Step 4: In loop, i =", i);
    sum += numbers[i];  // This will error when i = 3 (undefined)
}

console.log("Step 5: Loop finished");  // This won't run if there's an error above

If you see steps 1-3 but the program stops there, you know the problem is in the loop.

5.2 Common Types of JavaScript Errors

5.2.1 Syntax Errors

These occur when your code violates JavaScript’s grammar rules. The browser can’t even run your code when syntax errors are present. These are often the most frustrating for beginners because they prevent any code from running.

5.2.1.1 Missing or Mismatched Quotation Marks

Single vs. Double Quote Mismatches:

// Wrong - mixing quote types
let message = "Hello world';  // Error: starts with " but ends with '
let name = 'Alice";           // Error: starts with ' but ends with "

// Correct - matching quote types
let message = "Hello world";  // Both double quotes
let name = 'Alice';           // Both single quotes

5.2.1.2 Missing Brackets and Braces

Array Brackets [ ]:

// Wrong - missing closing bracket
let colors = ["red", "blue", "green";  // Error: missing ]
let numbers = [1, 2, 3, 4, 5;          // Error: missing ]

// Wrong - missing opening bracket
let colors = "red", "blue", "green"];  // Error: missing [

// Correct
let colors = ["red", "blue", "green"];

Object Braces { }:

// Wrong - missing closing brace
let person = {
    name: "Alice",
    age: 25
;  // Error: missing }

// Wrong - missing opening brace
let person = 
    name: "Alice",
    age: 25
};  // Error: missing {

// Correct
let person = {
    name: "Alice",
    age: 25
};

Function Parentheses ( ) and Braces { }:

// Wrong - missing closing parenthesis
function greet(name {  // Error: missing )
    console.log("Hello " + name);
}

// Wrong - missing closing brace
function greet(name) {
    console.log("Hello " + name);
  // Error: missing }

// Correct
function greet(name) {
    console.log("Hello " + name);
}

5.2.1.3 Complex Nested Structures

When you combine arrays, objects, and strings, tracking matching symbols becomes challenging:

Wrong - Multiple syntax errors:

let students = [
    {
        name: "Alice,          // Error: missing closing quote
        grades: [85, 92, 78,   // Error: missing closing bracket
        info: "Honor student"
    },  // Error: missing closing brace for first object
    {
        name: "Bob",
        grades: [76, 88, 91],
        info: "Regular student"
    }
;  // Error: missing closing bracket for arra

Correct version:

let students = [
    {
        name: "Alice",         // Fixed: added closing quote
        grades: [85, 92, 78],  // Fixed: added closing bracket
        info: "Honor student"
    },                         // Fixed: proper object closing
    {
        name: "Bob",
        grades: [76, 88, 91],
        info: "Regular student"
    }
];                            // Fixed: added closing bracket for array

Other Common Syntax Errors:

// Missing semicolon (usually not critical, but good practice)
let name = "John"
console.log(name)

// Missing comma in arrays or objects
let colors = ["red" "blue", "green"];  // Missing comma after "red"
let person = {
    name: "Alice"
    age: 25  // Missing comma after "Alice"
};

How to spot syntax errors: They usually prevent your code from running at all, and the browser console will show error messages like:

  • SyntaxError: Unexpected token
  • SyntaxError: Unterminated string literal
  • SyntaxError: Unexpected end of input
  • SyntaxError: Missing ) after argument list

5.2.2 Reference Errors

These happen when you try to use a variable that doesn’t exist or hasn’t been declared yet.

// Using a variable before declaring it
console.log(userName);  // ReferenceError: userName is not defined
let userName = "Alice";

// Misspelling a variable name
let favoriteColor = "blue";
console.log(favoritColor);  // ReferenceError: favoritColor is not defined

5.2.3 Type Errors

These occur when you try to perform an operation on a value that doesn’t support that operation.

// Trying to call a method on undefined
let person;
console.log(person.name);  // TypeError: Cannot read property 'name' of undefined

// Treating a number like a function
let age = 25;
age();  // TypeError: age is not a function

5.2.4 Logic Errors

These are the trickiest because your code runs without error messages, but it doesn’t do what you intended.

// Wrong comparison operator
let score = 85;
if (score = 90) {  // Should be == or ===, not =
    console.log("Perfect score!");
}

// Off-by-one errors in loops
for (let i = 1; i <= 5; i++) {  // If you meant to start at 0
    console.log("Item " + i);

5.2.5 Matching and Closing Syntax Errors

These are among the most common syntax errors beginners encounter, especially when working with complex data structures that mix text, arrays, and objects. JavaScript requires that every opening symbol has a matching closing symbol.

5.3 Debugging Strategies

5.3.1 Read Error Messages Carefully

Error messages might seem intimidating, but they contain valuable information:

Error message example: ReferenceError: userName is not defined // at script.js:5:13

This tells you:

  1. Type of error: ReferenceError
  2. What’s wrong: userName is not defined
  3. Where: script.js, line 5, character 13

5.3.2 Use console.log() for Debugging

This is your best friend for understanding what your code is actually doing:

let numbers = [1, 2, 3, 4, 5];
let sum = 0;

console.log("Starting sum:", sum);  // Check initial value

for (let i = 0; i < numbers.length; i++) {
    console.log("Current number:", numbers[i]);  // Check each iteration
    sum += numbers[i];
    console.log("Sum so far:", sum);  // Check running total
}

console.log("Final sum:", sum);  // Check final result

5.3.3 Visual Debugging for Syntax Errors

Use proper indentation to see structure clearly:

// Hard to debug - poor indentation
let data = [{name: "Alice", scores: [85, 92]}, {name: "Bob", scores: [76, 88]}];

// Easy to debug - good indentation
let data = [
    {
        name: "Alice", 
        scores: [85, 92]
    }, 
    {
        name: "Bob", 
        scores: [76, 88]
    }
];

Count your symbols. Every opening symbol needs a closing one:

let complex = [        // 1 opening [
    {                  // 1 opening {
        name: "test",  // quotes match ✓
        data: [1, 2]   // 1 opening [, 1 closing ] ✓
    }                  // 1 closing } ✓
];                     // 1 closing ] ✓

Use your code editor’s features:

  • Most editors highlight matching brackets/braces
  • Many editors show syntax errors with red underlines
  • Some editors auto-complete closing symbols

5.3.4 Check Your Variable Values

Often bugs happen because variables don’t contain what you think they do:

let userInput = "25";  // This is a string, not a number!
let age = userInput + 5;
console.log("Age:", age);  // Output: "255" (string concatenation)

// Debug by checking the type
console.log("Type of userInput:", typeof userInput);
console.log("Value of userInput:", userInput);

// Fix by converting to number
let age = parseInt(userInput) + 5;
console.log("Corrected age:", age);  // Output: 30

5.3.5 Isolate the Problem

When you have a lot of code, narrow down where the problem occurs:

// Instead of running everything at once, test parts separately
function calculateTotal(price, tax) {
    console.log("Price:", price, "Tax:", tax);  // Debug inputs
    let total = price + (price * tax);
    console.log("Calculated total:", total);    // Debug output
    return total;
}

// Test with known values
let result = calculateTotal(100, 0.08);
console.log("Final result:", result);

5.3.6 Use the Browser Developer Tools

Opening Developer Tools: - Chrome/Edge: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac) - Firefox: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)

Console Tab: Shows error messages and console.log() output
Sources Tab: Lets you set breakpoints to pause code execution

5.3.7 Step-by-Step Debugging Process

When you encounter a bug, follow this systematic approach:

  1. Read the error message (if there is one) and note the line number
  2. Check that line and the lines around it for obvious mistakes
  3. For syntax errors: Count opening and closing symbols - they should match
  4. Add console.log() statements before and after the problematic area
  5. Run your code and examine the console output
  6. Compare expected vs. actual values in your console logs
  7. Make one small change at a time and test again
  8. Remove debugging console.log() statements once the bug is fixed

5.3.8 Prevention Tips

  1. Write code in small pieces and test each piece before moving on
  2. Use meaningful variable names to avoid confusion
  3. Be consistent with your coding style (indentation, spacing, naming)
  4. Comment your code to remember what each part does
  5. Test with different inputs to catch edge cases

5.3.9 Common Beginner Debugging Mistakes

  • Assuming the error is complex when it’s often something simple like a typo
  • Changing multiple things at once instead of testing one change at a time
  • Not reading error messages carefully
  • Forgetting to save files before testing changes
  • Looking at the wrong file or line number

Remember: every programmer, no matter how experienced, spends time debugging. It’s a normal and important part of the development process. The key is to approach it systematically and learn from each bug you encounter.

5.4 Debugging Example

Let’s walk through debugging a common beginner mistake:

// Buggy code: trying to calculate average
let scores = [85, 92, 78, 96, 88];
let total = 0;

for (let i = 0; i <= scores.length; i++) {  // Bug: should be < not <=
    total += scores[i];
}

let average = total / scores.length;
console.log("Average:", average);  // Output: NaN (Not a Number)

Debugging steps:

// Step 1: Add debugging to see what's happening
let scores = [85, 92, 78, 96, 88];
let total = 0;

console.log("Array length:", scores.length);  // Debug: check array size

for (let i = 0; i <= scores.length; i++) {
    console.log("Index:", i, "Value:", scores[i]);  // Debug: check each iteration
    total += scores[i];
    console.log("Total so far:", total);  // Debug: check running total
}

let average = total / scores.length;
console.log("Final total:", total);  // Debug: check final total
console.log("Average:", average);

Console output reveals the problem:

Array length: 5
Index: 0 Value: 85
Total so far: 85
Index: 1 Value: 92
Total so far: 177
Index: 2 Value: 78
Total so far: 255
Index: 3 Value: 96
Total so far: 351
Index: 4 Value: 88
Total so far: 439
Index: 5 Value: undefined  // Problem! Index 5 doesn't exist
Total so far: NaN          // Adding undefined makes total NaN

The fix:

// Change <= to < in the loop condition
for (let i = 0; i < scores.length; i++) {  // Fixed!
    total += scores[i];
}