7

I would like to JSON.stringify all properties of an object, including those defined via getters. However, when I call JSON.stringify on an object, properties defined via getters are omitted:

> const obj = {key: 'val'}
undefined

> JSON.stringify(obj)
'{"key":"val"}'

> Object.defineProperty(obj, 'getter', {get: () => 'from getter'})
{ key: 'val' }

> obj.getter
'from getter'

> JSON.stringify(obj)
'{"key":"val"}'

I was hoping to see:

> JSON.stringify(obj)
'{"key":"val", "getter": "from getter"}'

Is this possible? Object.keys isn't detecting the getters either:

> Object.keys(obj)
[ 'key' ]

Can you query for getter keys? Or do you have to know their names ahead of time?

Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • 3
    The fact that it is a getter is irrelevant; the problem is that it's non-enumerable. (`Object.defineProperty` uses a default `enumerable: false`.) You want to enumerate non-enumerable properties (which can be done, but that's the description of your issue). – apsillers May 18 '16 at 19:00
  • 1
    perhaps make the property enumerable? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#Enumerable_attribute – ray May 18 '16 at 19:00
  • 1
    @apsillers: Make it an answer :) – Felix Kling May 18 '16 at 19:07
  • 1
    As a counter example to your getter theory, try `Object.defineProperty(obj, 'nogetter', {value: 'not a getter'})` – Felix Kling May 18 '16 at 19:08
  • 2
    While @apsillers answered the main question, you can query for getter keys by using [`Reflect.ownKeys()`](https://babeljs.io/repl/#?evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-1%2Cstage-2&code=const%20obj%20%3D%20%7Bkey%3A%20'val'%7D%3B%0AObject.defineProperty(obj%2C%20'getter'%2C%20%7Bget%3A%20()%20%3D%3E%20'from%20getter'%7D)%0A%0Aconsole.log(Reflect.ownKeys(obj))%3B) the same way you would use `Object.keys()`, except Reflect doesn't care if the property is enumerable or not. – Scott May 18 '16 at 19:11

1 Answers1

6

JSON.stringify only includes enumerable properties in its output.

When enumerable is not specified on the property descriptor passed into Object.defineProperty, it defaults to enumerable: false. Thus, any property definition done by Object.defineProperty (with a getter or not) will be non-enumerable unless you explicitly specify enumerable: true.

You can get all the properties that exist on an object (N.B: not inherited properties) with Object.getOwnPropertyNames or (in ES2015+) Reflect.ownKeys. (The only difference between these is that Reflect.ownKeys also includes properties defined by a Symbol key.) It is not possible to make JSON.stringify include non-enumerable properties; you must instead make the property enumerable.

Barmar
  • 741,623
  • 53
  • 500
  • 612
apsillers
  • 112,806
  • 17
  • 235
  • 239