1

I've defined an enumerable property in the prototype object and would like it to appear when I convert a prototyped object to JSON.

My first idea was to set it in toJSON but because I don't really want to keep it in the object afterwards I'll have to more or less clone the whole object in the function and set the necessary property.

Redefining the property in the target object and just proxying with the context of the current object doesn't seem to be an option as well, since I can't really use apply or call when getting dynamic properties.

Working solutions I could come up with so far seem to require quite an amount of code and aren't flexible and concise enough, so I'm wondering if there are any best practices of solving this task.

Here is an example which could seem a bit synthetic but still, I believe, conveys the idea:

function ProjectFolder() {
  this.files = [];
  Object.defineProperty(this, 'size', {enumerable: true, get: function() {
    return this.files.length;
  }});
}

function GithubProjectFolder() {
  this.files = ['.gitignore', 'README.md'];
}
GithubProjectFolder.prototype = new ProjectFolder();

var project1 = new ProjectFolder();
JSON.stringify(project1);
// output:  {"files":[],"size":0}
// size is present

var project = new GithubProjectFolder();    
JSON.stringify(project);
// output:  {"files":[".gitignore","README.md"]}
// size is absent
Miroshko
  • 863
  • 6
  • 14
  • 1
    possible duplicate of [How to stringify inherited objects to JSON?](http://stackoverflow.com/questions/8779249/how-to-stringify-inherited-objects-to-json) – Paul Draper May 03 '15 at 19:20
  • Remember that JSON is language-agnostic. It doesn't know anything about inheritance (prototypal or otherwise). Related: http://stackoverflow.com/questions/27161821/preserve-property-attributes-writeable-configurable-after-json-parse – Jared Smith May 03 '15 at 19:29
  • @JaderSmith sure that's clear, the question is how to prepare an inherited object so it's converted to JSON correctly. – Miroshko May 03 '15 at 19:39
  • @PaulDraper it's related but not 100% as the question you've mentioned doesn't cover calculating of dynamic properties in the proper context – Miroshko May 03 '15 at 19:39
  • @JaredSmith, but `JSON.stringify` is not language agnostic. And that is what he's using to generate the JSON. – Paul Draper May 03 '15 at 20:12
  • @Miroshko looks like your best option is writing your own `toJSON` function (or, actually, just a `toSimpleObject` function, and pass that to JSON) – mattsven May 03 '15 at 20:27

1 Answers1

2

I'll have to more or less clone the whole object in the function and set the necessary property.

Yes, and there's nothing wrong with that. That's how .toJSON is supposed to work:

ProjectFolder.prototype.toJSON = function toJSON() {
    var obj = {};
    for (var p in this) // all enumerable properties, including inherited ones
        obj[p] = this[p];
    return obj;
};

However, there are two other points I'd like to make:

  • The size of a folder doesn't really need to be stored separately in the JSON when it already is encoded in the length of the files array. This redundant data seems to be superfluous, and can confuse deserialisation. Unless something requires this property to be present, I'd recommend to simply omit it.
  • In ProjectFolders, the .size is an own property of each instance - in GithubProjectFolders it is not. This suggest that you're doing inheritance wrong. Better:

    function GithubProjectFolder() {
      ProjectFolder.call(this);
      this.files.puhs('.gitignore', 'README.md');
    }
    GithubProjectFolder.prototype = Object.create(ProjectFolder.prototype);
    

    If you'd fix that alone, the size will appear in the serialisation of your project.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375