直接用 class myerror extends error 是 es6 明确支持的最简洁写法,但需显式调用 super(message)、手动设置 this.name、避免覆盖 stack setter、推荐添加 status/isoperational/code 等语义属性,且禁止污染 error.prototype。

直接用 class MyError extends Error 是语法上最简洁的方式,也是 ES6 明确支持的写法。但“优雅”不只看能不能写,更要看是否健壮、可调试、可维护——尤其在生产环境。
必须调用 super() 并传入 message
子类构造函数中必须显式调用 super(message),否则实例不会正确初始化内部错误数据(如 stack、message),且 instanceof Error 可能返回 false(某些旧环境)。
class ValidationError extends Error {
constructor(message, field) {
super(message); // ✅ 关键:必须调用
this.name = 'ValidationError';
this.field = field;
this.status = 400;
}
}
手动补全 name 和堆栈信息(推荐)
虽然现代引擎大多自动设置 name,但压缩后类名可能被混淆(如变成 a)。显式赋值 this.name = 'ValidationError' 更可靠。
另外,ES6 不自动调用 Error.captureStackTrace(this, ValidationError)(Node.js 环境下),若需精准堆栈,可手动加:
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, ValidationError);
}
避免覆盖原生 toString() 或 stack 的 setter/getter
不要重写 Object.defineProperty(this, 'stack', {...}),容易破坏调试体验。优先用 get stack() 自定义逻辑,且保留原始堆栈主体:
get stack() {
return `${this.name}: ${this.message}\n${this.originalStack}`;
}
搭配 isOperational、status 等语义属性提升可读性
实际项目中建议统一结构,比如:
-
status: HTTP 状态码(如 401、500) -
isOperational: 标识是否为预期业务错误(便于中间件区分日志级别) -
code: 业务错误码(如'USER_NOT_FOUND')
这类扩展不靠继承实现,而是靠构造时赋值,干净、无副作用。
不推荐直接修改 Error.prototype
例如 Error.prototype.toJSON = function() {...} —— 这会污染全局,影响所有错误对象,且可能与 polyfill 或其他库冲突。封装或继承才是可控路径。
基本上就这些。











