1

env: nodejs 8.1.5, also tested on jscomplete with same results

const error = new Error("message");
const { message, ...rest } = error;
const keys = Object.keys(error);
const hasStack = error.hasOwnProperty("stack");

The rest object turns out to not include the stack property because Object.keys does not return it and a "for in" will not pick it up. It is, however, an own property of the error object (hasStack is true above).

What gives? I couldn't find anything about special-casing this property in the documentation or the polyfill on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

Pelle
  • 625
  • 1
  • 7
  • 17
  • `stack` is on `Error.prototype` and it is non-enumerable. The same reason you don't get `push` if you use `for...in` on an array – adiga Nov 05 '19 at 07:56
  • Some of the error properties like `lineno`, `colno`, `error` (for a *normal* thrown error, they don't look present on a `new Error`) are getters on the prototype, but the `message` and the `stack` aren't, they're directly on the error object – CertainPerformance Nov 05 '19 at 07:58
  • The typescript implementation tslib of ...rest uses for in so it won’t destructure non enumerable props. Good to know – Pelle Nov 05 '19 at 15:52

1 Answers1

4

It's not enumerable, so it won't be included in Object.keys or a for..in iteration:

const error = new Error("message");
// For Chrome, it's directly on the object:
console.log(Object.getOwnPropertyDescriptor(error, 'stack'));
// For Firefox, it's a getter on the prototype:
console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(error), 'stack'));

To iterate over all properties, including non-enumerable ones, use Object.getOwnPropertyNames instead:

// Chrome:
const error = new Error("message");
Object.getOwnPropertyNames(error).forEach((propName) => {
  console.log(propName);
});

On Firefox, those two properties are getters on the prototype, rather than being directly on the error object. (The prototype also has other properties other than stack and message)

// Chrome:
const error = new Error("message");
Object.getOwnPropertyNames(Object.getPrototypeOf(error)).forEach((propName) => {
  console.log(propName);
});
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320