1

So if I write a class as follows

class Rectangle {
   #width;
   #height;
   constructor() {
      this.#width = 3;
      this.#height = 5; 
   }

}

let rect = new Rectangle();

console.log(JSON.stringify(rect)); // returns {}

It will return an empty object, totally ignoring all of my private members. Adding a toJSON method works but that becomes very cumbersome. Is there any built-in way that I can easily get my private fields to show up in JSON.stringify? Or do I just have to write in every single member into a toJSON method?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Generally - don't try to `JSON.stringify` *instances* when possible, they're cumbersome to translate to and from JSON. If you *have* to use private fields, then yeah, you'll have to write them all out explicitly. Easier to use plain objects when possible IMO – CertainPerformance Nov 05 '21 at 02:29
  • @CertainPerformance This is what I was afraid of. The use of Classes and Instances would be extremely useful in the program I'm working on currently, but the hassle that they're giving me might not make them worth it. Thank you for the response. – Joshua Clark Nov 05 '21 at 02:41
  • Do not use private fields if you want `JSON.stringify` to access them!? – Bergi Nov 05 '21 at 04:25

3 Answers3

1

Private properties are only accessible inside the class declaration itself. You'll need to write your own serialization method:

class Rectangle {
  #width;
  #height;
  constructor() {
    this.#width = 3;
    this.#height = 5;
  }

  stringify() {
    return JSON.stringify({['#width']: this.#width,['#height']: this.#height})
  }

}

let rect = new Rectangle();

console.log(rect.stringify())
Spectric
  • 30,714
  • 6
  • 20
  • 43
  • 3
    This is what I ended up doing but with the toJSON method instead. I was just hoping I didn't have to write out every single member in every given class but if that's the case then I might end up forgoing private fields completely, which is a shame. – Joshua Clark Nov 05 '21 at 02:37
  • 2
    Isn’t the purpose of private fields is that they’re private? Doesn’t allowing serialisation undo that? – evolutionxbox Nov 05 '21 at 02:43
  • 1
    @evolutionxbox The use of private in my use-case is to keep those specific members from being tampered with at the instance level. Serializing them wouldn't necessarily break that for me. But I do see your point. – Joshua Clark Nov 05 '21 at 02:46
1

One option to avoid having to write out all the members would be to have a single private data property on the instance, and then serialize / deserialize that property:

class Rectangle {
   #data;
   constructor(data) {
      this.#data = data;
   }
   getWidth = () => this.#data.width;
   toJson = () => JSON.stringify(this.#data);
}
const r = new Rectangle({ width: 1, height: 1 });
console.log(r.getWidth());
const stringified = r.toJson();
console.log(stringified);

const restructured = new Rectangle(JSON.parse(stringified));
console.log(restructured.getWidth());
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thanks so much for the reply. I was also considering doing this. This may be the best solution if I want to keep using private members. I also thought about just adding all of my private fields to an object on construction and then updating that object every time I used a setter, but this also seemed like a pain. – Joshua Clark Nov 05 '21 at 03:20
  • You might want to change them from arrow functions to the `function` keyword so they have the correct `this` – MrMythical Nov 05 '21 at 03:26
  • 2
    @MrMythical They already do have the correct `this`. Inside a class field arrow function, `this` will always definitely refer to the instance. You can see for yourself by running the live snippet - press "Run code snippet". I prefer the arrow functions here because they're concise (no `function`, no `return`) – CertainPerformance Nov 05 '21 at 03:43
  • 2
    To add to what @CertainPerformance said. The `function` keyword is actually LESS likely to return the correct `this` than using the arrow operator. If you were to pass a `function` keyword as an argument in the class, any `this` you would use would fall back into the global scope. – Joshua Clark Nov 05 '21 at 03:50
-1

Don't use private variables; they're useless.

Dmitri
  • 479
  • 3
  • 10