JavaScript Debugging - Exercise 2

Buggy Code:

javascript

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

The variable i is declared with var, which has function scope, not block scope. By the time the setTimeout callbacks execute, the loop has already finished and i is 5. Fix: use let instead of var to create a new binding for each iteration.

Fixed Code:

javascript

for (let i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

Buggy Code:

javascript

function removeFirst(arr) {
  arr = arr.slice(1);
}
let numbers = [1, 2, 3, 4];
removeFirst(numbers);
console.log(numbers); // [1, 2, 3, 4]

Reassigning arr inside the function does not change the original array. The parameter arr is a local reference. Using slice creates a new array and assigns it to the local variable. Fix: use splice to mutate the original array in place.

Fixed Code:

javascript

function removeFirst(arr) {
  arr.splice(0, 1);
}
let numbers = [1, 2, 3, 4];
removeFirst(numbers);
console.log(numbers); // [2, 3, 4]

Buggy Code:

javascript

function countdown(n) {
  console.log(n);
  countdown(n - 1);
}
countdown(5);

The function has no base case to stop recursion. It will call itself indefinitely until a stack overflow occurs. Fix: add a base case.

Fixed Code:

javascript

function countdown(n) {
  if (n < 0) return;
  console.log(n);
  countdown(n - 1);
}
countdown(5);

Buggy Code:

javascript

let items = [1, 2, 3];
if (typeof items === "array") {
  console.log("array");
} else {
  console.log(typeof items);
}

In JavaScript, typeof returns "object" for arrays because arrays are a special kind of object. To check if a value is an array, use Array.isArray().

Fixed Code:

javascript

let items = [1, 2, 3];
if (Array.isArray(items)) {
  console.log("array");
} else {
  console.log(typeof items);
}

Buggy Code:

javascript

let numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] === 2) {
    numbers.splice(i, 1);
  }
  console.log(numbers[i]);
}

When splice removes the element at index 1 (value 2), all subsequent elements shift left. The element that was at index 2 (value 3) moves to index 1. But i increments to 2, so the value 3 is skipped. Fix: decrement i after splicing, or iterate in reverse.

Fixed Code:

javascript

let numbers = [1, 2, 3, 4, 5];
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] === 2) {
    numbers.splice(i, 1);
    i--;
    continue;
  }
  console.log(numbers[i]);
}

Buggy Code:

javascript

let jsonStr = "{'name': 'Alice', 'age': 25}";
let user = JSON.parse(jsonStr);
console.log(user.name);

JSON requires double quotes for both keys and string values. Single quotes are not valid JSON syntax. JSON.parse will throw a SyntaxError.

Fixed Code:

javascript

let jsonStr = '{"name": "Alice", "age": 25}';
let user = JSON.parse(jsonStr);
console.log(user.name);

Buggy Code:

javascript

function isEven(num) {
  if (num % 2 = 0) {
    return true;
  } else {
    return false;
  }
}
console.log(isEven(4));

The code uses a single = (assignment) instead of === (comparison) inside the if condition. This causes a syntax error in strict mode or unexpected behavior. Fix: use ===.

Fixed Code:

javascript

function isEven(num) {
  if (num % 2 === 0) {
    return true;
  } else {
    return false;
  }
}
console.log(isEven(4));

Buggy Code:

javascript

let user = {
  name: "Alice",
  greet: function() {
    setTimeout(function() {
      console.log("Hello, " + this.name);
    }, 1000);
  }
};
user.greet(); // "Hello, undefined"

Regular functions inside setTimeout lose the this context of the enclosing object. The this inside the callback refers to the global object (or undefined in strict mode). Fix: use an arrow function, which inherits this from the surrounding scope.

Fixed Code:

javascript

let user = {
  name: "Alice",
  greet: function() {
    setTimeout(() => {
      console.log("Hello, " + this.name);
    }, 1000);
  }
};
user.greet(); // "Hello, Alice"

Buggy Code:

javascript

let price = "100";
let tax = "10";
let total = price + tax;
console.log(total); // "10010"

Both price and tax are strings. The + operator performs string concatenation instead of addition, producing "10010" instead of 110. Fix: convert the strings to numbers first.

Fixed Code:

javascript

let price = "100";
let tax = "10";
let total = Number(price) + Number(tax);
console.log(total); // 110

Buggy Code:

javascript

try {
  setTimeout(function() {
    throw new Error("Something went wrong");
  }, 1000);
} catch (e) {
  console.log("Caught: " + e.message);
}

The try-catch block only catches synchronous errors. By the time the setTimeout callback executes, the try-catch block has already finished. The error is thrown in a separate execution context. Fix: move the try-catch inside the callback.

Fixed Code:

javascript

setTimeout(function() {
  try {
    throw new Error("Something went wrong");
  } catch (e) {
    console.log("Caught: " + e.message);
  }
}, 1000);