在 JavaScript 中,错误处理是一种重要的编程实践,它可以帮助我们优雅地处理程序运行时可能出现的异常情况。
try...catch 是 JavaScript 中最基本的错误处理机制。
try {// 可能抛出错误的代码const result = someFunction();console.log(result);} catch (error) {// 处理错误console.error('发生错误:', error.message);}
function divide(a, b) {if (b === 0) {throw new Error('除数不能为零');}return a / b;}try {console.log(divide(10, 2)); // 5console.log(divide(10, 0)); // 抛出错误} catch (error) {console.error('计算错误:', error.message); // 计算错误: 除数不能为零}
finally 块中的代码无论是否发生错误都会执行,通常用于清理资源。
let fileHandle;try {fileHandle = openFile('data.txt');processFile(fileHandle);} catch (error) {console.error('处理文件时出错:', error.message);} finally {// 无论是否发生错误,都关闭文件if (fileHandle) {closeFile(fileHandle);}}
可以在 try 块内部嵌套另一个 try...catch 结构。
try {try {throw new Error('内部错误');} catch (innerError) {console.error('捕获到内部错误:', innerError.message);throw new Error('外部错误'); // 重新抛出错误}} catch (outerError) {console.error('捕获到外部错误:', outerError.message);}
JavaScript 提供了多种内置的错误类型,每种类型用于表示特定类型的错误。
Error 是所有错误类型的基类。
const error = new Error('发生错误');console.log(error.name); // 'Error'console.log(error.message); // '发生错误'console.log(error.stack); // 错误堆栈
TypeError 表示值的类型不符合预期。
try {const num = 42;num.toLowerCase(); // 数字没有 toLowerCase 方法} catch (error) {console.log(error instanceof TypeError); // trueconsole.log(error.message); // 'num.toLowerCase is not a function'}
ReferenceError 表示引用了一个不存在的变量。
try {console.log(undefinedVariable); // 未定义的变量} catch (error) {console.log(error instanceof ReferenceError); // trueconsole.log(error.message); // 'undefinedVariable is not defined'}
SyntaxError 表示语法错误。
try {eval('if (true) {'); // 语法错误} catch (error) {console.log(error instanceof SyntaxError); // trueconsole.log(error.message); // 'Unexpected token }'}
RangeError 表示数值超出有效范围。
try {const arr = new Array(-1); // 数组长度不能为负数} catch (error) {console.log(error instanceof RangeError); // trueconsole.log(error.message); // 'Invalid array length'}
错误可以从一个函数传播到另一个函数,直到被捕获或到达全局作用域。
function level3() {throw new Error('level3 错误');}function level2() {try {level3();} catch (error) {console.log('level2 捕获错误:', error.message);throw error; // 重新抛出错误}}function level1() {try {level2();} catch (error) {console.log('level1 捕获错误:', error.message);}}level1();// level2 捕获错误: level3 错误// level1 捕获错误: level3 错误
可以通过继承 Error 类来创建自定义错误类型。
class ValidationError extends Error {constructor(message) {super(message);this.name = 'ValidationError';}}function validateUser(user) {if (!user.name) {throw new ValidationError('用户名不能为空');}if (!user.email) {throw new ValidationError('邮箱不能为空');}if (!user.email.includes('@')) {throw new ValidationError('邮箱格式不正确');}}try {validateUser({ name: '', email: 'invalid-email' });} catch (error) {if (error instanceof ValidationError) {console.error('验证错误:', error.message);} else {console.error('未知错误:', error.message);}}
try {// 可能抛出错误的代码processData();} catch (error) {// 只处理预期的错误if (error instanceof ValidationError) {console.error('验证错误:', error.message);} else {// 重新抛出未预期的错误throw error;}}
function divide(a, b) {if (typeof a !== 'number' || typeof b !== 'number') {throw new TypeError(`参数必须是数字,但收到了 ${typeof a} 和 ${typeof b}`);}if (b === 0) {throw new Error('除数不能为零');}return a / b;}try {divide('10', 2);} catch (error) {console.error(error.message); // 参数必须是数字,但收到了 string 和 number}
function logError(error, context = {}) {console.error('错误时间:', new Date().toISOString());console.error('错误类型:', error.name);console.error('错误消息:', error.message);console.error('错误堆栈:', error.stack);console.error('上下文信息:', context);// 在实际应用中,可以将错误发送到服务器或日志服务// sendErrorToServer(error, context);}try {// 可能抛出错误的代码processData();} catch (error) {logError(error, { userId: 123, action: 'processData' });}
下面是一个简单的用户注册系统,你需要实现错误处理来验证用户输入并处理可能的错误。