What it does: Prevents your script from crashing when errors happen - lets you handle them gracefully instead of the dreaded “script dies.”

How try…catch Actually Works:

Basic Structure:

try {
  // Code that might break
  let result = riskyOperation();
  console.log("Success!");
} catch (err) {
  // Handle the error
  console.log("Something went wrong:", err.message);
}
// Script continues running here

The Error Object Properties:

What You Get in catch:

try {
  nonExistentFunction();
} catch (err) {
  console.log(err.name);    // "ReferenceError"
  console.log(err.message); // "nonExistentFunction is not defined"
  console.log(err.stack);   // Full call stack trace
  console.log(err);         // "ReferenceError: nonExistentFunction is not defined"
}

Creating Your Own Errors (throw):

Custom Error Creation:

let json = '{"age": 30}'; // Missing name property
 
try {
  let user = JSON.parse(json); // Valid JSON, but incomplete data
  
  if (!user.name) {
    throw new Error("Incomplete data: no name"); // Custom error!
  }
  
  console.log("Hello", user.name);
} catch (err) {
  console.log("Error:", err.message); // "Error: Incomplete data: no name"
}

Different Error Types:

javascript

throw new Error("General error");
throw new SyntaxError("Custom syntax error");
throw new ReferenceError("Custom reference error");
throw new TypeError("Custom type error");
 
// Can even throw primitives (but don't!)
throw "Just a string";
throw 404;
throw true;

Rethrowing Pattern:

Only Handle Errors You Know:

javascript

try {
  let user = JSON.parse(jsonData);
  
  if (!user.name) {
    throw new SyntaxError("Incomplete data: no name");
  }
  
  unknownVariable; // Programming mistake!
  
} catch (err) {
  if (err instanceof SyntaxError) {
    console.log("Data error:", err.message); // Handle data errors
  } else {
    throw err; // Rethrow programming errors - don't hide bugs!
  }
}

try…catch…finally:

finally ALWAYS Runs:

javascript

let start = Date.now();
 
try {
  // Some operation that might fail
  riskyOperation();
  return "success"; // Even with return, finally runs!
} catch (err) {
  return "error";   // Even with return, finally runs!
} finally {
  let duration = Date.now() - start;
  console.log(`Operation took ${duration}ms`); // ALWAYS executes
}

try…finally (without catch):

Cleanup Without Error Handling:

function doSomething() {
  startExpensiveResource();
  
  try {
    // Do work that might fail
    complexOperation();
  } finally {
    cleanupExpensiveResource(); // Always cleanup, even if error occurs
  }
  // If error occurred, it bubbles up after cleanup
}

Global Error Handling:

Catch All Uncaught Errors:

window.onerror = function(message, url, line, col, error) {
  console.log(`Global error: ${message} at ${url}:${line}:${col}`);
  // Send to error logging service
  return true; // Prevents default browser error handling
};
 
// Modern way (better):
window.addEventListener('error', function(event) {
  console.log('Global error:', event.error);
});

Interview Gotchas:

// Gotcha 1: Syntax errors can't be caught
try {
  if (true { // Missing )
} catch (err) {
  console.log("Won't work"); // Script won't even parse
}
 
// Gotcha 2: Async errors escape
try {
  setTimeout(() => { throw new Error("Async error"); }, 100);
} catch (err) {
  console.log("Won't catch async errors");
}
 
// Gotcha 3: finally runs even with return
function test() {
  try {
    return 1;
  } finally {
    console.log("This runs first!"); // Runs before return
  }
}
 
// Gotcha 4: Variable scope
try {
  let x = 1;
} catch (err) {
  let y = 2;
} finally {
  let z = 3;
}
// x, y, z are not accessible here!
 
// Gotcha 5: Rethrowing preserves original stack
try {
  throw new Error("Original");
} catch (err) {
  throw err; // Preserves original stack trace
  // vs
  throw new Error(err.message); // Creates new stack trace
}

Never Get Tricked - Follow These Rules:

  1. Syntax errors kill before try…catch - code must be valid JavaScript
  2. Async needs its own try…catch - setTimeout, promises escape outer try…catch
  3. finally ALWAYS runs - even with return statements
  4. Rethrow unknown errors - don’t hide programming bugs
  5. Use specific error types - SyntaxError, TypeError, etc. for different scenarios
  6. Global handlers for fallback - catch what you missed

Bottom line: try…catch is for expected failures, finally is for cleanup, throw is for custom errors, and rethrowing prevents hiding bugs.