JavaScript 错误处理

错误是编程的日常——好的错误处理让程序在异常发生时优雅降级,而不是崩溃消失。

try...catch

javascript
try {
  // 尝试执行的代码
  const result = riskyOperation();
  console.log(result);
} catch (error) {
  // 出错时执行
  console.error('操作失败:', error.message);
}

try...catch 只捕获同步执行的错误。对于 setTimeout、Promise(未 await 时)等异步操作中的错误,try...catch 无法捕获——需要用 Promise 的 .catch() 或在 async 函数内部使用 try...catch

throw — 主动抛出异常

javascript
function divide(a, b) {
  if (b === 0) {
    throw new Error('除数不能为零');
  }
  return a / b;
}

try {
  console.log(divide(10, 0));
} catch (error) {
  console.error(error.message); // "除数不能为零"
}

Error 对象

javascript
const error = new Error('出错了');

error.name;    // "Error"
error.message; // "出错了"
error.stack;   // 调用堆栈(调试时非常有用)

内置错误类型

类型触发场景
Error通用错误
TypeError类型错误:操作了不合法类型的值
ReferenceError引用错误:访问了不存在的变量
SyntaxError语法错误:代码语法有问题
RangeError范围错误:数值超出允许范围
javascript
try {
  undefined.name;         // TypeError
  console.log(xyz);       // ReferenceError
  JSON.parse('123abc');   // SyntaxError
  (42).toFixed(200);      // RangeError
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}

自定义错误类型

javascript
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

function validateUser(user) {
  if (!user.name) {
    throw new ValidationError('用户名不能为空');
  }
  if (user.age < 0) {
    throw new ValidationError('年龄不能为负数');
  }
}

finally

finally 块中的代码无论是否出错都会执行

javascript
function processData() {
  startLoading();

  try {
    const data = fetchAndParse();
    return data;
  } catch (error) {
    console.error(error);
    return null;
  } finally {
    stopLoading(); // 始终会执行——关闭 loading 动画、释放资源
  }
}

全局错误捕获

javascript
// 捕获未被 try...catch 处理的错误(主要用于日志上报)
window.addEventListener('error', (event) => {
  console.error('全局错误:', event.message);
  // 可上报到日志服务
});

// 捕获未被处理的 Promise rejection
window.addEventListener('unhandledrejection', (event) => {
  console.error('未处理的 Promise 拒绝:', event.reason);
});

调试技巧

console 方法

javascript
console.log('普通日志');
console.warn('警告');
console.error('错误'); // 红色背景,附带堆栈
console.table([{ a: 1, b: 2 }, { a: 3, b: 4 }]); // 表格展示

const user = { name: '张三', age: 25 };
console.log('用户:', user); // 对象引用(展开看当前值)
console.dir(user); // 对象详细结构

// 计时
console.time('operation');
// ... 执行操作 ...
console.timeEnd('operation'); // "operation: 12.34ms"

// 分组
console.group('用户信息');
console.log('姓名:张三');
console.log('年龄:25');
console.groupEnd();

使用 debugger

在代码中加入 debugger 语句,浏览器开发者工具打开时会在该行暂停执行:

javascript
function calculateTotal(items) {
  let total = 0;
  for (const item of items) {
    debugger; // 在此暂停,可逐步检查变量
    total += item.price;
  }
  return total;
}

浏览器断点

在 DevTools → Sources 面板中点击行号设置断点,在 Console 中直接访问断点处的变量值。这是定位复杂 bug 最高效的方法。