2

I have the following JavaScript classes

class Driver {

   constructor() {
      this._name = null;
      this._car = null;
   }

   setName(name) {
      this._name = name;
   }

   getName() {
      return this._name;
   }

   setCar(car) {
       this._car = car;
   }

   getCar() {
       return this._car;
   }
}

class Car {
   constructor() {
      this._model = null;
   }

   setModel(model) {
      this._model = model;
   }

   getModel(model) {
      return this._model;
   }
}

And I want to solve two problems:

  1. Having the following json object {name:"Boo", car:{model:"Foo"}} I want to get driver object of Driver class with car object of Car class.
  2. Having Driver object with Car object I want to get json like {name:"Boo", car:{model:"Foo"}}.

Is it possible to do automatically? I mean without writing code for every field of every class?

Pavel_K
  • 8,216
  • 6
  • 44
  • 127
  • You have to do these things manually. Property names don't even match (_name vs name). See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior for instance to json conversion. – Estus Flask Mar 10 '18 at 11:51
  • Possible duplicate of [Parse JSON String into a Particular Object Prototype in JavaScript](https://stackoverflow.com/questions/5873624/parse-json-string-into-a-particular-object-prototype-in-javascript) – PhmNgocNghia Mar 10 '18 at 11:56
  • @PhmNgocNghia Read again the question and remove the duplicate. – Pavel_K Mar 10 '18 at 11:59

1 Answers1

2

This is absolutely possible since Javascript provides full reflection capabilities for classes and dynamic class and method invocation.

JSON classes simply provide syntactic sugar over the object prototyping as noted here: (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). But, there is also a new reflection API that can help, though it is very similar to the Object methods from before (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect).

You can iterate over each property and convert to json recursively this way-- which requires holding to the convention of '_' prefixes for properties of the object (you could easily modify it to handle both prefixed and unprefixed). If you instead want to use the getters for the class instead of simply stripping the properties, see the example at the bottom using a similar dynamic invocation on the class using the properties as a guide:

  function transformUnderscoreProperties(object)
  {
    var returnable = {};
    for (var property in object) {
      if (object.hasOwnProperty(property)) {
        if(property.charAt(0) === '_'){
          let name = property.substr(1); //Property name without _
          if( typeof object[property] === 'object' )
          {
            returnable[name] = transformUnderscoreProperties( object[property] );
          }
          else returnable[name] = object[property];
        }
      }
    }
    return returnable;
  }
  function recursiveObjectStringify( object ) {
    return JSON.stringify( transformUnderscoreProperties( object ) );
  }

If you want to do it the other way, you can construct classes from dynamic name using the solution here (Instantiate a JavaScript Object Using a String to Define the Class Name), and call dynamic methods on the object as is here (Javascript dynamically invoke object method from string), but this requires keeping to a strict naming convention of camel case for setter methods and naming the properties of the json after the class to which they should be transformed:

  function classFromObject( object, className ){
    className = capitalizeFirstLetter( className );
    var returnable = window[className];
    for (var property in object ) {
      if (object.hasOwnProperty(property)) {
        if( typeof object[property] === "object" ){
          returnable["set"+capitalizeFirstLetter(property)]( classFromObject( object[property], property ) ); //Calls "setCar()" on the object returned from the car being made into a class
        }
        else
          returnable["set"+capitalizeFirstLetter(property)]( object[property] ); //Calls "setName()" on the object with the property value.
      }
    }
    return returnable;
  }

  function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }

(and a shoutout to How do I make the first letter of a string uppercase in JavaScript? for the first letter capitalization)

EDIT: If you want to use the getters in reading the properties instead of just reading the properties directly, this example shows that, (I've come this far, might as well show the example for it):

  function transformUnderscorePropertiesGetters(object)
  {
    var returnable = {};
    for (var property in object) {
      if (object.hasOwnProperty(property)) {
        if(property.charAt(0) === '_'){
          let name = property.substr(1); //Property name without _
          if( typeof object[property] === 'object' )
          {
            returnable[name] = transformUnderscoreProperties( object["get" + capitalizeFirstLetter](name) );
          }
          else returnable[name] = object["get" + capitalizeFirstLetter](name)();
        }
      }
    }
    return returnable;
  }
  function recursiveObjectStringifyGetters( object ) {
    return JSON.stringify( transformUnderscorePropertiesGetters( object ) );
  }
Halcyon
  • 1,218
  • 13
  • 19