摘要:
本文系统解析 JavaScript 错误对象体系,深入剖析 7 大内置错误类型的使用场景与差异,通过原型继承实现企业级自定义异常,结合堆栈追踪、错误编码等高级技巧,构建可维护的错误处理策略。
一、Error 对象:错误处理基石
核心结构解析:
javascript
class Error {
constructor(message) {
this.name = "Error";
this.message = message || "默认错误";
this.stack = ""; // 非标准但广泛支持
}
}
// 实例属性扩展
const err = new Error("文件未找到");
err.file = "config.json";
err.code = "ENOENT";
关键特性对比:
特性 | 描述 | 浏览器支持 | Node.js 支持 |
---|---|---|---|
name | 错误类型标识 | 全支持 | 全支持 |
message | 人类可读的错误描述 | 全支持 | 全支持 |
stack | 调用堆栈信息 | IE10+ | 全支持 |
fileName | 引发错误的文件路径 | Firefox, Safari | ❌ |
lineNumber | 引发错误的行号 | Firefox, Safari | ❌ |
堆栈追踪优化技巧:
javascript
function captureStack() {
const originalPrepare = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const err = new Error();
Error.captureStackTrace(err, captureStack); // 跳过当前函数
const stack = err.stack;
Error.prepareStackTrace = originalPrepare;
return stack.map(frame => ({
file: frame.getFileName(),
line: frame.getLineNumber(),
column: frame.getColumnNumber(),
function: frame.getFunctionName()
}));
}
console.log(captureStack());
// 输出: [{file: "app.js", line: 20, function: "main"}]
二、七大内置错误类型详解
1. SyntaxError:语法解析错误
javascript
// 常见触发场景
JSON.parse('{name: "Alice"}'); // 缺少双引号
eval("const 123var = 1;"); // 非法标识符
诊断技巧:
javascript
try {
// 可能出错的代码
} catch (err) {
if (err instanceof SyntaxError) {
console.error("语法错误:", err.message);
const match = err.message.match(/at position (\d+)/);
if (match) highlightError(match[1]);
}
}
2. TypeError:类型操作错误
javascript
// 典型用例
null.property; // 空值访问
const fn = 123; fn(); // 非函数调用
Object.freeze({}).prop=1; // 不可写属性赋值
防御性编程模式:
javascript
function safeAccess(obj, propChain) {
return propChain.split(".").reduce(
(acc, prop) => acc?.[prop],
obj
) ?? defaultValue;
}
safeAccess(user, "address.city"); // 不会抛出TypeError
3. ReferenceError:引用不存在
javascript
// 常见场景
console.log(notDefined); // 未声明变量
window.undefinedVar; // 浏览器全局不存在
严格模式增强:
javascript
"use strict";
undeclaredVar = 10; // 抛出ReferenceError (非严格模式创建全局变量)
4. RangeError:数值越界
javascript
// 触发条件
new Array(-1); // 非法数组长度
(123.45).toFixed(200); // 超出0-100范围
边界检查工具函数:
javascript
function assertRange(value, min, max) {
if (value < min || value > max) {
throw new RangeError(
`值 ${value} 超出范围 [${min}, ${max}]`
);
}
}
assertRange(array.length, 0, MAX_SIZE);
5. URIError:URI处理错误
javascript
decodeURIComponent("%"); // 无效URI序列
encodeURI("\uD800"); // 代理对错误
安全URI处理方案:
javascript
function safeDecode(uri) {
try {
return decodeURIComponent(uri);
} catch (err) {
if (err instanceof URIError) {
return uri; // 或返回清理后的版本
}
throw err;
}
}
6. EvalError:eval执行错误 (已弃用)
javascript
// 历史遗留 (ES5+不再抛出)
try {
throw new EvalError("旧式错误");
} catch (err) {
console.warn("兼容性处理:", err.name);
}
7. AggregateError:多错误聚合 (ES2021)
javascript
const promises = [
Promise.reject(new Error("错误1")),
Promise.reject(new TypeError("错误2"))
];
Promise.any(promises).catch(err => {
if (err instanceof AggregateError) {
err.errors.forEach((e, i) => {
console.error(`错误#${i+1}:`, e.message);
});
}
});
三、自定义错误类型实战
企业级错误基类实现:
javascript
class AppError extends Error {
constructor(message, code = "GENERIC_ERROR", status = 500) {
super(message);
this.name = this.constructor.name;
this.code = code;
this.status = status;
this.timestamp = new Date().toISOString();
Error.captureStackTrace(this, this.constructor);
}
toJSON() {
return {
name: this.name,
code: this.code,
message: this.message,
status: this.status,
timestamp: this.timestamp
};
}
}
// 使用示例
throw new AppError("用户未认证", "AUTH_REQUIRED", 401);
领域特定错误扩展:
javascript
class DatabaseError extends AppError {
constructor(message, query) {
super(message, "DB_OPERATION_FAILED", 503);
this.query = query;
}
toJSON() {
return {
...super.toJSON(),
query: this.query
};
}
}
class ValidationError extends AppError {
constructor(field, value, rule) {
super(`字段 ${field} 验证失败`, "VALIDATION_ERROR", 400);
this.details = [{ field, value, rule }];
}
addError(field, value, rule) {
this.details.push({ field, value, rule });
return this;
}
}
// 使用示例
const err = new ValidationError("email", "invalid", "email格式")
.addError("password", "short", "至少8字符");
console.log(err.toJSON());
/*
{
name: "ValidationError",
code: "VALIDATION_ERROR",
message: "字段 email 验证失败",
status: 400,
details: [
{ field: "email", value: "invalid", rule: "email格式" },
{ field: "password", value: "short", rule: "至少8字符" }
]
}
*/
四、错误处理高级模式
1. 错误码标准化体系
javascript
// 错误码注册表
const ERROR_CODES = {
// 认证类错误
AUTH_REQUIRED: { status: 401, message: "需要认证" },
INVALID_TOKEN: { status: 403, message: "无效令牌" },
// 数据库错误
DB_CONN_FAIL: { status: 503, message: "数据库连接失败" },
// 业务规则错误
INSUFFICIENT_BALANCE: { status: 400, message: "余额不足" }
};
function createError(code, details) {
const spec = ERROR_CODES[code];
if (!spec) throw new Error(`未知错误码: ${code}`);
const err = new AppError(
details?.message || spec.message,
code,
spec.status
);
if (details) Object.assign(err, details);
return err;
}
// 使用示例
throw createError("INSUFFICIENT_BALANCE", {
userId: 123,
required: 100,
actual: 50
});
2. 错误恢复策略模式
javascript
const strategies = {
// 重试策略
retry: (error, maxAttempts = 3) => {
return function(action) {
let attempts = 0;
while (attempts < maxAttempts) {
try {
return action();
} catch (err) {
if (++attempts >= maxAttempts) throw err;
console.warn(`重试中 (${attempts}/${maxAttempts})...`);
}
}
};
},
// 后备值策略
fallback: (value) => () => value,
// 断路器模式
circuitBreaker: (threshold = 5, timeout = 10000) => {
let failures = 0;
let lastFailure = 0;
return function(action) {
if (failures >= threshold && Date.now() - lastFailure < timeout) {
throw new Error("服务熔断中");
}
try {
const result = action();
failures = 0; // 重置计数器
return result;
} catch (err) {
failures++;
lastFailure = Date.now();
throw err;
}
};
}
};
// 使用示例
const fetchWithRetry = strategies.retry(new Error("超时"), 2);
fetchWithRetry(() => fetch("/api"));
3. 错误监控集成
javascript
class ErrorMonitor {
constructor(service) {
this.service = service;
this.breadcrumbs = [];
}
recordBreadcrumb(message) {
this.breadcrumbs.push({
message,
timestamp: Date.now(),
context: { url: location.href }
});
}
capture(err, level = "error") {
const report = {
error: {
name: err.name,
message: err.message,
stack: err.stack
},
level,
breadcrumbs: this.breadcrumbs,
context: {
appState: store.getState(),
user: currentUser
}
};
this.service.send(report);
this.breadcrumbs = []; // 清空面包屑
}
wrap(fn) {
return (...args) => {
try {
return fn(...args);
} catch (err) {
this.capture(err);
throw err;
}
};
}
}
// 集成示例
const monitor = new ErrorMonitor(SentryService);
monitor.recordBreadcrumb("用户点击支付按钮");
const safeHandler = monitor.wrap(function() {
throw new Error("支付失败");
});
button.addEventListener("click", safeHandler);
五、生产环境最佳实践
1. 错误分类处理策略

2. 安全错误信息策略
javascript
// 开发环境显示完整错误
function devError(err) {
return {
status: err.status,
error: err.name,
message: err.message,
stack: err.stack,
details: err.details
};
}
// 生产环境过滤敏感信息
function prodError(err) {
const safeResponse = {
status: err.status,
code: err.code
};
// 保留业务安全消息
if (err.isOperational) {
safeResponse.message = err.message;
} else {
safeResponse.message = "系统内部错误";
}
return safeResponse;
}
// Express中间件
app.use((err, req, res, next) => {
const isProd = process.env.NODE_ENV === "production";
res.status(err.status || 500)
.json(isProd ? prodError(err) : devError(err));
});
3. 错误生命周期管理
javascript
// 错误处理流水线
function handleError(err) {
// 步骤1: 丰富上下文
enrichError(err);
// 步骤2: 分类处理
if (err instanceof NetworkError) {
return handleNetworkError(err);
}
if (err instanceof BusinessError) {
return handleBusinessError(err);
}
// 步骤3: 监控上报
errorMonitor.capture(err);
// 步骤4: 恢复或终止
if (isRecoverable(err)) {
return recoveryProcedure();
}
terminateApplication();
}
// 未捕获错误的最后防线
process.on("uncaughtException", err => {
handleError(err);
if (!isRecoverable(err)) process.exit(1);
});
结语
JavaScript 错误处理是构建健壮应用的核心技能,本文涵盖:
- 7 大内置错误类型的深度解析
- 企业级自定义错误实现方案
- 错误码标准化与恢复策略
- 生产环境监控与安全实践
关键认知:优秀错误处理不仅是技术实现,更是用户体验的核心组成。当错误信息能帮助用户明确下一步行动时,系统才真正实现韧性设计。
本文是 JavaScript 错误处理领域的终极指南,如果对您有帮助,请点赞收藏支持!关注作者获取更多工程化深度内容。