JavaScript: JavaScript Errors and Debugging

Writing bug-free code is impossible — even the creator of JavaScript produced the typeof null === "object" bug in just 10 days. So learning to find bugs and handle errors is even more important than learning to write code.

1. Error Handling and Debugging

(1) Common Error Types

Error Type Cause Example
SyntaxError Invalid syntax if (true { — mismatched parentheses
ReferenceError Accessing a non-existent variable console.log(notExist)
TypeError Operating on the wrong type undefined.toString()
RangeError Value out of valid range new Array(-1)

SyntaxError is caught before code execution (parsing phase). The other three are runtime errors.

(2) try...catch...finally

Use try...catch to catch runtime errors and prevent your program from crashing:

HTML
<script>
try {
  const data = JSON.parse('{bad json}');
} catch (error) {
  console.log("Parse failed:", error.message);
} finally {
  console.log("Cleanup work");
}
</script>

The error object in catch has two commonly used properties:

(3) throw — Manually Throwing Errors

try...catch can only catch runtime errors, but business logic errors need to be thrown manually:

HTML
<script>
function setAge(age) {
  if (typeof age !== "number" || age < 0) {
    throw new Error("Age must be a positive number");
  }
  console.log("Age set to: " + age);
}

try {
  setAge(-5);
} catch (e) {
  console.log(e.message);
}
</script>

throw can throw any value, but using new Error() or its subclasses is recommended — they include stack trace information.

(4) Custom Error Messages

Use subclasses of Error or custom properties to provide richer error information:

HTML
<script>
class ValidationError extends Error {
  constructor(field, message) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

try {
  throw new ValidationError("email", "Invalid email format");
} catch (e) {
  console.log(e.name + " [" + e.field + "]: " + e.message);
}
</script>

(5) Browser DevTools (F12)

Panel Purpose
Console View logs, execute code, see errors
Sources Set breakpoints, step through code, inspect variables
Network Inspect network requests, response status, load times
Elements View/modify DOM and styles

Breakpoint debugging is the most powerful debugging technique: click a line number in the Sources panel to set a breakpoint, refresh the page, and the code pauses at that point — step through line by line, inspect variables, and examine the call stack.

(6) The console Family

Method Purpose
console.log() General output
console.warn() Warning (yellow)
console.error() Error (red)
console.table() Display arrays/objects as a table
console.time() / console.timeEnd() Timing
console.group() / console.groupEnd() Grouped output
console.clear() Clear the console

console.table is especially useful for displaying arrays of objects — far more readable than log.

(7) Debugging Tips


▶ Example: try/catch for JSON Parsing

HTML 📖 Display only
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>JSON Parsing</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .demo { max-width: 600px; margin: 16px auto; }
    textarea { width: 100%; height: 120px; padding: 12px; font-size: 14px; font-family: monospace; border: 2px solid #ccc; border-radius: 6px; resize: vertical; box-sizing: border-box; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; margin: 8px 4px; }
    .parse { background: #4a90d9; color: #fff; }
    .parse:hover { background: #357abd; }
    .bad { background: #d9534f; color: #fff; }
    .bad:hover { background: #c9302c; }
    .result { margin-top: 16px; padding: 16px; border-radius: 8px; }
    .success { background: #d4edda; border: 2px solid #5cb85c; }
    .error-box { background: #f8d7da; border: 2px solid #d9534f; }
    .error-type { font-weight: bold; color: #721c24; }
    .error-msg { margin-top: 4px; color: #721c24; }
  </style>
</head>
<body>
  <h2 style="text-align:center;">JSON Parse Error Handling</h2>
  <div class="demo">
    <textarea id="jsonInput">{
  "name": "Alice",
  "age": 20,
  "skills": ["JavaScript", "HTML", "CSS"]
}</textarea>
    <div style="text-align:center;">
      <button class="parse" id="parseBtn">Parse JSON</button>
      <button class="bad" id="badBtn">Insert Invalid JSON</button>
    </div>
    <div id="result"></div>
  </div>
  <script>
    function parseJSON(jsonStr) {
      try {
        const data = JSON.parse(jsonStr);
        return { success: true, data: data };
      } catch (error) {
        return { success: false, name: error.name, message: error.message };
      }
    }

    document.getElementById("parseBtn").addEventListener("click", function() {
      var input = document.getElementById("jsonInput").value;
      var result = parseJSON(input);
      var output = document.getElementById("result");

      if (result.success) {
        output.className = "result success";
        output.innerHTML = "<strong>Parse successful!</strong><pre>" +
          JSON.stringify(result.data, null, 2) + "</pre>";
      } else {
        output.className = "result error-box";
        output.innerHTML = '<div class="error-type">' + result.name +
          '</div><div class="error-msg">' + result.message + '</div>';
      }
    });

    document.getElementById("badBtn").addEventListener("click", function() {
      document.getElementById("jsonInput").value = '{name: "Alice", age: 20}';
    });
  </script>
</body>
</html>
64 logic lines (exceeds 40-line limit, display only)

▶ Example: Custom Errors and Form Validation

HTML 📖 Display only
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Custom Errors</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .form { max-width: 440px; margin: 16px auto; padding: 24px; background: #f9f9f9; border-radius: 12px; }
    .row { margin: 12px 0; }
    label { display: block; margin-bottom: 4px; font-weight: bold; }
    input { width: 100%; padding: 10px 12px; font-size: 16px; border: 2px solid #ccc; border-radius: 6px; box-sizing: border-box; }
    input.valid { border-color: #5cb85c; }
    input.invalid { border-color: #d9534f; }
    .field-error { color: #d9534f; font-size: 13px; margin-top: 2px; min-height: 20px; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; background: #4a90d9; color: #fff; width: 100%; margin-top: 8px; }
    button:hover { background: #357abd; }
    .global-msg { margin-top: 12px; padding: 12px; border-radius: 6px; text-align: center; }
    .global-ok { background: #d4edda; color: #155724; }
    .global-fail { background: #f8d7da; color: #721c24; }
  </style>
</head>
<body>
  <h2 style="text-align:center;">Custom Error Validation</h2>
  <div class="form">
    <div class="row">
      <label>Username (3–20 characters):</label>
      <input type="text" id="username" placeholder="Enter username" />
      <div class="field-error" id="usernameErr"></div>
    </div>
    <div class="row">
      <label>Age (0–150):</label>
      <input type="text" id="age" placeholder="Enter age" />
      <div class="field-error" id="ageErr"></div>
    </div>
    <div class="row">
      <label>Email:</label>
      <input type="text" id="email" placeholder="Enter email" />
      <div class="field-error" id="emailErr"></div>
    </div>
    <button id="submitBtn">Submit</button>
    <div class="global-msg" id="globalMsg"></div>
  </div>
  <script>
    class ValidationError extends Error {
      constructor(field, message) {
        super(message);
        this.name = "ValidationError";
        this.field = field;
      }
    }

    function validateUsername(value) {
      if (!value.trim()) throw new ValidationError("username", "Username cannot be empty");
      if (value.trim().length < 3) throw new ValidationError("username", "Username must be at least 3 characters");
      if (value.trim().length > 20) throw new ValidationError("username", "Username must be at most 20 characters");
    }

    function validateAge(value) {
      if (!value.trim()) throw new ValidationError("age", "Age cannot be empty");
      var num = Number(value);
      if (isNaN(num)) throw new ValidationError("age", "Please enter a valid number");
      if (num < 0 || num > 150) throw new ValidationError("age", "Age range: 0–150");
      if (!Number.isInteger(num)) throw new ValidationError("age", "Age must be an integer");
    }

    function validateEmail(value) {
      if (!value.trim()) throw new ValidationError("email", "Email cannot be empty");
      if (!value.includes("@")) throw new ValidationError("email", "Email must contain @");
      if (!value.includes(".")) throw new ValidationError("email", "Invalid email format");
    }

    var validators = {
      username: validateUsername,
      age: validateAge,
      email: validateEmail
    };

    function clearErrors() {
      ["username", "age", "email"].forEach(function(field) {
        document.getElementById(field).className = "";
        document.getElementById(field + "Err").textContent = "";
      });
      document.getElementById("globalMsg").innerHTML = "";
      document.getElementById("globalMsg").className = "global-msg";
    }

    document.getElementById("submitBtn").addEventListener("click", function() {
      clearErrors();
      var hasError = false;

      ["username", "age", "email"].forEach(function(field) {
        var value = document.getElementById(field).value;
        try {
          validators[field](value);
          document.getElementById(field).className = "valid";
        } catch (e) {
          hasError = true;
          document.getElementById(field).className = "invalid";
          document.getElementById(field + "Err").textContent =
            e.name + ": " + e.message;
        }
      });

      var msg = document.getElementById("globalMsg");
      if (hasError) {
        msg.className = "global-msg global-fail";
        msg.textContent = "Form has errors — please fix and retry";
      } else {
        msg.className = "global-msg global-ok";
        msg.textContent = "All fields passed validation!";
      }
    });
  </script>
</body>
</html>
107 logic lines (exceeds 40-line limit, display only)

▶ Example: Error Types Quick Reference and console Methods

HTML 📖 Display only
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Error Types & Console</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .section { margin: 20px 0; }
    table { border-collapse: collapse; width: 100%; max-width: 700px; }
    td, th { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
    th { background: #4a90d9; color: #fff; }
    .trigger { background: #f8d7da; }
    .safe { background: #d4edda; }
    button { padding: 6px 16px; border: none; border-radius: 4px; cursor: pointer; margin: 2px; font-size: 14px; }
    .btn-err { background: #d9534f; color: #fff; }
    .btn-safe { background: #5cb85c; color: #fff; }
    .btn-info { background: #5bc0de; color: #fff; }
    .output { margin-top: 12px; padding: 12px; background: #1a1a2e; color: #e0e0e0; border-radius: 6px; font-family: monospace; font-size: 13px; min-height: 60px; max-height: 200px; overflow-y: auto; }
    .log-line { margin: 2px 0; }
    .log-warn { color: #f0ad4e; }
    .log-error { color: #d9534f; }
    .log-info { color: #5bc0de; }
  </style>
</head>
<body>
  <h2>Error Types & Console Methods Demo</h2>

  <div class="section">
    <h3>Common Error Types</h3>
    <table>
      <tr><th>Error Type</th><th>Trigger Code</th><th>try/catch Result</th></tr>
      <tr class="trigger"><td>SyntaxError</td><td><code>JSON.parse("{bad")</code></td><td id="r1"></td></tr>
      <tr class="trigger"><td>ReferenceError</td><td><code>notExistVar</code></td><td id="r2"></td></tr>
      <tr class="trigger"><td>TypeError</td><td><code>undefined.toString()</code></td><td id="r3"></td></tr>
      <tr class="trigger"><td>RangeError</td><td><code>new Array(-1)</code></td><td id="r4"></td></tr>
    </table>
  </div>

  <div class="section">
    <h3>console Methods (Simulated Output)</h3>
    <button class="btn-info" onclick="simLog('log', 'Regular log')">console.log</button>
    <button class="btn-info" onclick="simLog('warn', 'Warning message')">console.warn</button>
    <button class="btn-err" onclick="simLog('error', 'Error message')">console.error</button>
    <button class="btn-info" onclick="simLog('info', 'Info message')">console.info</button>
    <button class="btn-safe" onclick="simTable()">console.table</button>
    <button class="btn-safe" onclick="simTime()">console.time</button>
    <button class="btn-info" onclick="clearSim()">Clear</button>
    <div class="output" id="simConsole"></div>
  </div>

  <script>
    var tests = [
      function() { JSON.parse("{bad"); },
      function() { notExistVar; },
      function() { var x; x.toString(); },
      function() { new Array(-1); }
    ];

    var ids = ["r1", "r2", "r3", "r4"];
    var names = ["SyntaxError", "ReferenceError", "TypeError", "RangeError"];

    tests.forEach(function(fn, i) {
      try {
        fn();
        document.getElementById(ids[i]).textContent = "Not triggered (unexpected)";
      } catch (e) {
        document.getElementById(ids[i]).innerHTML =
          '<span class="safe">' + e.name + ": " + e.message + '</span>';
      }
    });

    function simLog(type, msg) {
      var cls = type === "warn" ? "log-warn" :
                type === "error" ? "log-error" : "log-info";
      var prefix = type === "warn" ? "⚠" :
                   type === "error" ? "✖" : "ℹ";
      addLine(prefix + " " + msg, cls);
      if (type !== "error") {
        // Visual output shown via addLine above
      }
    }

    function simTable() {
      var data = [
        { name: "Alice", age: 20, score: 90 },
        { name: "Bob", age: 22, score: 85 },
        { name: "Charlie", age: 21, score: 95 }
      ];
      addLine("console.table:", "log-info");
      data.forEach(function(d) {
        addLine("  " + d.name + " | " + d.age + " | " + d.score, "log-info");
      });
      // Visual output shown above
    }

    function simTime() {
      console.time("demo");
      var sum = 0;
      for (var i = 0; i < 1000000; i++) { sum += i; }
      console.timeEnd("demo");
      addLine("⏱ console.time/timeEnd: 1,000,000 additions done", "log-info");
    }

    function addLine(text, cls) {
      var div = document.getElementById("simConsole");
      div.innerHTML += '<div class="log-line ' + (cls || "") + '">' + text + '</div>';
      div.scrollTop = div.scrollHeight;
    }

    function clearSim() {
      document.getElementById("simConsole").innerHTML = "";
    }
  </script>
</body>
</html>
103 logic lines (exceeds 40-line limit, display only)

❓ FAQ

Q Can try...catch catch SyntaxError?
A No. SyntaxError is thrown during the parsing phase before execution even begins, so the try block is never reached. However, if a SyntaxError occurs at runtime (e.g. JSON.parse fails, or new Function("bad syntax")), it can be caught.
Q When should I use finally?
A When you need cleanup operations to run regardless of whether an error occurred — closing files, releasing resources, hiding loading states. For most simple scenarios, catch alone is sufficient.
Q What's the difference between throw and return?
A return is for normal flow — the caller handles the returned value. throw is for abnormal flow — it skips subsequent code and walks up the call stack looking for a catch. Use throw for errors, return for normal results.

📖 Summary

📝 Exercises

  1. Write a function safeDivide(a, b) that uses try...catch to handle division by zero (hint: dividing by zero in JS doesn't throw — you need to check and throw yourself). Return the result or an error message.
  2. Write a function safeJSONParse(str) that parses a JSON string. On failure, return { success: false, error: <error message> }. On success, return { success: true, data: <parsed result> }.
  3. Write a function retry(fn, times): execute fn, and if it throws, retry up to times times. If all attempts fail, throw the last error. Implement with try...catch.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏