Error Handling - Exercise 1

An error in JavaScript is a problem that occurs when code cannot run as expected. Errors can happen due to wrong syntax, missing variables, invalid operations, or unexpected data types. JavaScript stops running at the point where it encounters an error.

javascript

// This code will cause an error
console.log(myVariable); // ReferenceError: myVariable is not defined

// This will also cause an error
let number = 10;
number.toUpperCase(); // TypeError: number.toUpperCase is not a function

// Errors stop further code from running
console.log("This line runs");
undefinedFunction(); // Error here
console.log("This line will NOT run");

The try...catch statement lets you handle errors without stopping your entire program. The try block contains code that might cause an error, and the catch block runs if an error occurs. This way your code can recover from problems gracefully.

javascript

// Without try...catch (program crashes)
// undefinedFunction(); // This would stop everything

// With try...catch (program continues)
try {
  undefinedFunction(); // This causes an error
} catch (error) {
  console.log("An error occurred!"); // This runs instead of crashing
}

console.log("Program continues running!"); // This still runs

To write a try...catch block, put the risky code inside the try block and error handling code inside the catch block. The catch block receives an error object that contains details about what went wrong.

javascript

// Basic try...catch structure
try {
  // Code that might cause an error
  let result = riskyOperation();
  console.log(result);
} catch (error) {
  // Code that runs if an error occurs
  console.log("Something went wrong:", error.message);
}

// Practical example
try {
  let data = JSON.parse("invalid json");
} catch (error) {
  console.log("Could not parse JSON:", error.message);
  // Output: Could not parse JSON: Unexpected token i in JSON at position 0
}

The Error object is a built in JavaScript object that contains information about an error. It has properties like name and message that describe what kind of error occurred and why. You can create your own Error objects using the new keyword.

javascript

// Creating a new Error object
let myError = new Error("Something went wrong");

console.log(myError); // Error: Something went wrong
console.log(myError.name); // "Error"
console.log(myError.message); // "Something went wrong"

// Error objects in catch blocks
try {
  throw new Error("Custom error message");
} catch (error) {
  console.log(error.name); // "Error"
  console.log(error.message); // "Custom error message"
}

You can access the error message using the message property of the error object. This property contains a human readable string that describes what went wrong. It is useful for displaying error information to users or logging.

javascript

// Accessing error.message
try {
  let obj = undefined;
  obj.property; // This will throw an error
} catch (error) {
  console.log(error.message);
  // Output: Cannot read properties of undefined (reading 'property')
}

// Using message for user friendly errors
try {
  JSON.parse("{invalid}");
} catch (error) {
  console.log("Error: " + error.message);
  // Output: Error: Unexpected token i in JSON at position 1
}

You can access the error name using the name property of the error object. This property tells you the type of error that occurred, such as TypeError, ReferenceError, or SyntaxError. It helps you identify and handle different error types appropriately.

javascript

// Accessing error.name
try {
  undefinedVariable; // Using an undefined variable
} catch (error) {
  console.log(error.name); // "ReferenceError"
}

try {
  null.toString(); // Calling method on null
} catch (error) {
  console.log(error.name); // "TypeError"
}

// Using name to handle different errors
try {
  riskyCode();
} catch (error) {
  if (error.name === "TypeError") {
    console.log("Type error occurred");
  } else if (error.name === "ReferenceError") {
    console.log("Reference error occurred");
  }
}

The finally block is code that runs after try and catch, regardless of whether an error occurred or not. It always executes, making it perfect for cleanup tasks like closing files or connections. You can use it with or without a catch block.

javascript

// finally always runs
try {
  console.log("Try block");
  throw new Error("Oops!");
} catch (error) {
  console.log("Catch block");
} finally {
  console.log("Finally block"); // This always runs
}
// Output: Try block, Catch block, Finally block

// finally runs even without errors
try {
  console.log("No error here");
} catch (error) {
  console.log("This does not run");
} finally {
  console.log("Finally still runs");
}
// Output: No error here, Finally still runs

The throw statement lets you create and throw your own errors. You can throw an Error object with a custom message, or throw any value like a string or number. When you throw an error, the code stops and looks for a catch block to handle it.

javascript

// Throwing a custom error
function divide(a, b) {
  if (b === 0) {
    throw new Error("Cannot divide by zero");
  }
  return a / b;
}

try {
  let result = divide(10, 0);
} catch (error) {
  console.log(error.message); // "Cannot divide by zero"
}

// Throwing different values
throw new Error("Error object");
throw "Just a string";
throw 404;
throw { code: 500, message: "Server error" };

A SyntaxError occurs when your code has invalid JavaScript syntax that the browser cannot understand. This happens before the code runs, during the parsing phase. Common causes include missing brackets, typos in keywords, or incorrect punctuation.

javascript

// Examples of SyntaxError (these would break your code)

// Missing closing bracket
// if (true { console.log("error"); }

// Typo in keyword
// funtion myFunc() { }

// Missing quotes
// let name = Hello;

// SyntaxError from JSON.parse
try {
  JSON.parse("{ invalid json }");
} catch (error) {
  console.log(error.name); // "SyntaxError"
  console.log(error.message); // Details about the syntax problem
}

A ReferenceError occurs when you try to use a variable that does not exist or has not been declared. This often happens due to typos in variable names, using variables before they are defined, or accessing variables outside their scope.

javascript

// Using an undefined variable
try {
  console.log(undeclaredVariable);
} catch (error) {
  console.log(error.name); // "ReferenceError"
  console.log(error.message); // "undeclaredVariable is not defined"
}

// Typo in variable name
let userName = "John";
try {
  console.log(userNme); // Typo: missing 'a'
} catch (error) {
  console.log(error.name); // "ReferenceError"
}

// Variable out of scope
function myFunction() {
  let localVar = "local";
}
// console.log(localVar); // ReferenceError: localVar is not defined

A TypeError occurs when you perform an operation on a value of the wrong type. This happens when you call methods on null or undefined, use a non function as a function, or try operations that do not work with that data type.

javascript

// Calling a method on null
try {
  let value = null;
  value.toString();
} catch (error) {
  console.log(error.name); // "TypeError"
  console.log(error.message); // "Cannot read properties of null"
}

// Calling a non function as a function
try {
  let number = 42;
  number();
} catch (error) {
  console.log(error.name); // "TypeError"
  console.log(error.message); // "number is not a function"
}

// Wrong method for data type
try {
  let num = 100;
  num.toUpperCase(); // Numbers do not have toUpperCase
} catch (error) {
  console.log(error.name); // "TypeError"
}

A RangeError occurs when a value is not within the allowed range. This happens with invalid array lengths, too much recursion, or number methods with out of range arguments. JavaScript throws this error when values exceed acceptable limits.

javascript

// Invalid array length
try {
  let arr = new Array(-1); // Negative length not allowed
} catch (error) {
  console.log(error.name); // "RangeError"
  console.log(error.message); // "Invalid array length"
}

// Number method out of range
try {
  let num = 1.5;
  num.toFixed(200); // Max is 100
} catch (error) {
  console.log(error.name); // "RangeError"
}

// Too much recursion (stack overflow)
try {
  function recurse() {
    recurse(); // Calls itself forever
  }
  recurse();
} catch (error) {
  console.log(error.name); // "RangeError" (Maximum call stack size exceeded)
}