ES5扩展JavaScript内置Error:代码块C是否必要?疑问解答
关于ES5扩展内置Error时代码块C的必要性解答
先看你提供的ES5扩展Error的代码:
// Start: Code Chunk A function CustomError(foo, message, fileName, lineNumber) { var instance = new Error(message, fileName, lineNumber); instance.foo = foo; Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); if (Error.captureStackTrace) { Error.captureStackTrace(instance, CustomError); } return instance; } // End: Code Chunk A // Start: Code Chunk B CustomError.prototype = Object.create(Error.prototype, { constructor: { value: Error, enumerable: false, writable: true, configurable: true } }); // End: Code Chunk B // Start: Code Chunk C // Is the following necessary? if (Object.setPrototypeOf){ Object.setPrototypeOf(CustomError, Error); } else { CustomError.__proto__ = Error; } // End: Code Chunk C
下面针对你的两个问题逐一解答:
问题1:已执行代码块B,代码块C是否必要?
答案是:不是必须的——但要不要加完全取决于你的实际需求:
- 如果你的代码只需要保证
CustomError的实例能正常继承Error的实例方法(比如toString()、访问message属性),并且通过instanceof检查实例是否属于Error,那代码块C完全可以去掉。你测试的结果也验证了这一点:不管有没有C,实例的原型链都是error -> CustomError.prototype -> Error.prototype,已经满足了实例层面的核心继承需求。 - 但如果你的场景需要以下特性,那代码块C就有必要了:
- 希望
CustomError能直接调用Error的静态方法/属性(比如CustomError.name、或者后续新增的Error静态方法) - 需要
CustomError instanceof Error返回true(没有C的话,这个表达式会返回false,因为构造函数本身的原型链没指向Error) - 要让
Object.getPrototypeOf(CustomError)返回Error,而非默认的Function.prototype
- 希望
问题2:代码块B和C的作用关联
这两个代码块其实是在处理原型链的完全不同的层面,互不冲突:
- 代码块B:管的是实例的原型链。它把
CustomError.prototype设置为一个以Error.prototype为原型的对象,同时修正了constructor属性。这样一来,所有通过CustomError创建的实例,都能继承Error.prototype上的实例方法和属性,保证实例的行为和原生Error一致。 - 代码块C:管的是构造函数本身的原型链。它把
CustomError这个函数的[[Prototype]](也就是__proto__)指向Error构造函数,让CustomError作为一个函数,能继承Error构造函数的静态属性和方法,同时让构造函数本身的原型链和原生Error对齐。
简单来说,B决定了“用CustomError造出来的对象是什么样”,C决定了“CustomError这个构造函数本身是什么样”。这也是为什么你测试实例的__proto__时,有没有C结果都一样——因为C根本没碰实例的原型链。
内容的提问来源于stack exchange,提问作者jmtoung
相关产品推荐
相关产品推荐

