扩展Error类后解构错误对象Chrome正常Firefox失效,如何兼容?
Ah, this is a classic cross-browser gotcha when extending native Error classes in ES6! Let's break down why this happens and how to fix it so your code works consistently across Chrome and Firefox.
Why does this difference occur?
The root issue lies in how different browsers handle the this binding when extending the native Error class:
- In Chrome, when you call
super(message)in yourFakeErrorconstructor,thisdirectly references your customFakeErrorinstance. Any properties you assign tothis(likedescription) are own enumerable properties of that instance, so they get included when using the spread operator (...error). - In Firefox, the
super(message)call creates a native Error object, and thethisin your constructor is initially tied to that native object instead of yourFakeErrorinstance. When you setthis.description, it gets attached to the native Error object—not your actualFakeErrorinstance. Since the spread operator only copies properties that belong directly to the object (not inherited ones),descriptiongets left out of the destructured result.
How to fix it for all browsers?
There are two reliable approaches to resolve this cross-browser inconsistency:
1. Fix the prototype chain explicitly
The simplest fix is to set the prototype of your FakeError instance to match your custom class's prototype after calling super(). This ensures this behaves as a proper instance of your subclass across all browsers:
class FakeError extends Error { constructor(message, opts = {}) { super(message); // Fix the prototype chain to point to FakeError instead of native Error Object.setPrototypeOf(this, FakeError.prototype); const { description = null } = opts; this.description = description; Error.captureStackTrace(this, this.constructor); } } (() => { try { throw new FakeError('Test', { description: 'This is a test' }); } catch (error) { console.log({ ...error, test: 'test' }); } })();
2. Use a custom serialization method
If you want to avoid Object.setPrototypeOf (it has negligible performance costs for most use cases, but some developers prefer this approach), add a custom method to convert your error to a plain object with all relevant properties:
class FakeError extends Error { constructor(message, opts = {}) { super(message); const { description = null } = opts; this.description = description; Error.captureStackTrace(this, this.constructor); } // Serialize error to a plain object with all custom properties toPlainObject() { return { message: this.message, description: this.description, stack: this.stack, // Add any other custom properties you need here }; } } (() => { try { throw new FakeError('Test', { description: 'This is a test' }); } catch (error) { console.log({ ...error.toPlainObject(), test: 'test' }); } })();
Both methods will ensure your description property is included in the destructured/spread object consistently across Chrome, Firefox, and other modern browsers.
内容的提问来源于stack exchange,提问作者Matt Fletcher

