Error handling and debugging in JavaScript

Coding Exercises on JavaScript Error Handling and Debugging

Basic try…catch Implementation

Task: Write a JavaScript function that attempts to parse a JSON string and uses try…catch to handle any errors that arise.

Purpose: Understand how to catch and handle errors gracefully in a controlled manner.

Sample Code:

function parseJSON(jsonString) {

    try {

        let jsonObj = JSON.parse(jsonString);

        console.log(“JSON parsed successfully:”, jsonObj);

    } catch (error) {

        console.error(“Failed to parse JSON:”, error);

    }

}

parseJSON(‘{“name”:”John”, “age”:30}’); // Valid JSON

parseJSON(‘{“name”: “John”, “age”: 30’); // Invalid JSON

Explanation:

This code tries to parse a JSON string. If the JSON is valid, it logs the parsed object. If parsing fails (e.g., due to syntax errors), the error is caught by the catch block, which then logs an error message.

Using finally Block

Task: Implement a finally block that runs after try…catch to clean up resources, regardless of whether an error occurred.

Purpose: Demonstrate the use of finally to perform cleanup activities.

Sample Code:

function loadData(url) {

    try {

        // Simulate loading data

        console.log(`Loading data from ${url}`);

        throw new Error(“Network error”);

    } catch (error) {

        console.error(“An error occurred:”, error.message);

    } finally {

        console.log(“Cleanup actions completed”);

    }

}

loadData(“https://api.example.com/data”);

Explanation:

In this example, the finally block executes after the try and catch blocks, ensuring that cleanup code runs regardless of whether an error occurred during the data loading process.

Throwing Custom Errors

Task: Write a function that checks the age parameter and throws a custom error if the age is less than 18.

Purpose: Practice throwing custom errors based on specific conditions.

Sample Code:

function verifyAge(age) {

    try {

        if (age < 18) {

            throw new Error(“You must be 18 years or older.”);

        }

        console.log(“Age verified:”, age);

    } catch (error) {

        console.error(“Verification failed:”, error.message);

    }

}

verifyAge(21); // Passes verification

verifyAge(16); // Fails verification

Explanation:

This function uses a conditional check within a try block to throw a custom error if the age is below 18. The catch block handles this error by logging an appropriate message.

Nested try…catch Blocks

Task: Utilize nested try…catch blocks to handle different types of errors in complex code sections.

Purpose: Show how nested try…catch structures can be used to differentiate error handling strategies.

Sample Code:

function processFile(data) {

    try {

        console.log(“Processing data…”);

        try {

            let result = JSON.parse(data);

            console.log(“Data processed:”, result);

        } catch (parseError) {

            throw new Error(“Data parsing failed.”);

        }

    } catch (error) {

        console.error(“Error:”, error.message);

    }

}

processFile(‘{“valid”: “json”}’);

processFile(‘invalid json’);

Explanation:

The outer try block handles broader processing tasks, while the inner try block specifically attempts to parse JSON data, each with its own error handling logic.

Error Handling in Asynchronous Code

Task: Use try…catch within an asynchronous function to handle errors in promises.

Purpose: Explore error handling in asynchronous operations using async/await.

Sample Code:

async function fetchData(url) {

    try {

        let response = await fetch(url);

        let data = await response.json();

        console.log(“Data fetched successfully:”, data);

    } catch (error) {

        console.error(“Failed to fetch data:”, error);

    }

}

fetchData(“https://api.example.com/data”);

Explanation:

This asynchronous function attempts to fetch data from a URL and parse it as JSON. If either the network request or the parsing fails, the error is caught and handled in the catch block.

Multiple Choice Quiz Questions

What does the catch block do in a try…catch statement?

A) Executes a function if no errors were thrown in the try block

B) Catches and handles any errors thrown in the try block

C) Displays all errors as alerts in the browser

D) Sends errors to external logging services

Correct Answer: B) Catches and handles any errors thrown in the try block

Explanation: The catch block is designed to intercept and handle any errors that occur within the preceding try block, allowing for graceful error handling.

What is the purpose of the finally block in error handling?

A) To throw any unhandled errors

B) To perform clean-up operations after executing the try and catch blocks

C) To execute additional try blocks

D) To handle errors instead of the catch block

Correct Answer: B) To perform clean-up operations after executing the try and catch blocks

Explanation: The finally block is used to execute code after the try and catch blocks have completed, regardless of whether an error was caught.

What will happen if you throw an error without a catch block to handle it?

A) The error will be ignored

B) The error will be logged in the console automatically

C) The program will continue execution normally

D) The error will cause the program to terminate or the script to stop executing

Correct Answer: D) The error will cause the program to terminate or the script to stop executing

Explanation: Throwing an error without a corresponding catch block to handle it will result in the script stopping execution, potentially causing the program to terminate.

Which of the following is true about custom errors in JavaScript?

A) They cannot be caught by catch blocks

B) They are only for displaying errors and cannot contain logic

C) They can be used to create specific error types and messages

D) They are automatically logged to external systems

Correct Answer: C) They can be used to create specific error types and messages

Explanation: Custom errors allow developers to throw specific error types with custom messages, enhancing error handling by making it easier to understand and manage the errors that occur.

How should you handle errors in asynchronous code that uses promises?

A) Errors in promises cannot be caught

B) Use a catch method chained to the promise

C) Errors in promises are automatically handled by the browser

D) Use a timeout to catch errors

Correct Answer: B) Use a catch method chained to the promise

Explanation: Errors in promises should be handled using the catch method chained to the promise or within a try…catch block in an async function, ensuring that errors are caught and managed appropriately.

Coding Exercises on JavaScript Functions

Basic Function Definition and Invocation

Task: Write a JavaScript function named greet that prints “Hello, World!” to the console.

Purpose: Learn how to define and call a simple function.

Sample Code:

function greet() {

    console.log(“Hello, World!”);

}

greet(); // Function invocation

Explanation:

This exercise demonstrates the basic structure of a function in JavaScript. The greet function is defined using the function keyword followed by the name of the function. It encapsulates a console log statement and is called (invoked) by its name followed by parentheses.

Function with Parameters

Task: Define a function named add that takes two parameters and returns their sum.

Purpose: Practice writing functions that take parameters and understand how to return a value.

Sample Code:

function add(a, b) {

    return a + b;

}

console.log(add(5, 3)); // Outputs 8

Explanation:

The add function demonstrates functions with parameters and a return statement. It receives two arguments, a and b, adds them, and returns the sum. The return statement sends this value back to where the function was called.

Default Parameters

Task: Create a function named multiply that multiplies two numbers. Assign a default value of 1 to both parameters.

Purpose: Understand default parameter values in functions.

Sample Code:

function multiply(a = 1, b = 1) {

    return a * b;

}

console.log(multiply(4)); // Outputs 4

console.log(multiply(4, 5)); // Outputs 20

Explanation:

This function utilizes default parameters. If the function is called with less than two arguments, the missing arguments are assigned a default value of 1. This prevents errors and allows the function to operate with fewer inputs.

Scope of Variables Inside Functions

Task: Demonstrate the scope of a variable by defining a variable inside a function and trying to access it outside the function.

Purpose: Explore the concept of local scope within functions.

Sample Code:

function showNumber() {

    let num = 10; // Local variable

    console.log(num); // Accessible here

}

showNumber();

console.log(num); // Error: num is not defined

Explanation:

The variable num is defined inside the showNumber function, making it local to that function. It cannot be accessed outside the function, illustrating the concept of local scope.

Function Expression

Task: Write a function expression that calculates the square of a number and use it immediately after.

Purpose: Understand function expressions and how they differ from function declarations.

Sample Code:

const square = function(num) {

    return num * num;

};

console.log(square(4)); // Outputs 16

Explanation:

This exercise shows a function expression where the function is assigned to the variable square. Unlike function declarations, function expressions are not hoisted, meaning they cannot be called before they are defined in the code.

Multiple Choice Quiz Questions

What will happen if you try to call a function before it is defined in JavaScript?

A) It will throw an error.

B) It will return undefined.

C) It will work if it’s a function declaration.

D) It will work only if it’s a function expression.

Correct Answer: C) It will work if it’s a function declaration

Explanation: Function declarations are hoisted in JavaScript, which means they are moved to the top of their containing scope during the compile phase, allowing them to be called before they are defined.

What is a correct example of a function with default parameters?

A) function multiply(a, b = 1) { return a * b; }

B) function multiply(a = 1, b) { return a * b; }

C) function multiply(a, b) { return a * b = 1; }

D) function multiply(a = 1, b) { return a * b = 1; }

Correct Answer: A) function multiply(a, b = 1) { return a * b; }

Explanation: This is the correct way to set default parameters in JavaScript functions. The second parameter b is given a default value of 1.

What does the following function return?

function checkNum(num) {

    if (num > 10) {

        return true;

    }

}

console.log(checkNum(8));

A) true

B) false

C) undefined

D) 0

Correct Answer: C) undefined

Explanation: Since the condition num > 10 is not met and there is no else part, the function returns undefined for any input less than or equal to 10.

Which statement about the scope of variables in JavaScript is true?

A) Variables defined inside a function are accessible globally.

B) Variables defined with var inside a function are local to the function.

C) Variables defined with let inside a function can be accessed anywhere in the script.

D) Global variables can only be accessed inside functions.

Correct Answer: B) Variables defined with var inside a function are local to the function

Explanation: Variables declared with var inside a function have local scope to that function, meaning they can only be accessed within that function.

Which is an example of a function expression in JavaScript?

A) function add(a, b) { return a + b; }

B) const subtract = function(a, b) { return a – b; };

C) subtract(a, b) { return a – b; }

D) function multiply(a, b);

Correct Answer: B) const subtract = function(a, b) { return a – b; };

Explanation: A function expression involves defining a function and assigning it to a variable, as shown in option B. Unlike function declarations, function expressions are not hoisted.