Search code examples
javascriptes6-classmonkeypatchingprototypal-inheritance

Create instance of ES6 class from JSON result


What's the easiest way to create an instance of an ES6 class from a JSON object? E.g., given something like:

class Foo
  constructor(bar) {
    this.bar = bar
  }
  frob() {
    console.log(`frobbed ${this.bar}`)
  }
}

and an API call returning:

{ "bar": "baz" }

how can I get the equivalent of something like this?

let foo = new Foo("baz")

I.e., something like:

async function frobResult() {
  let result = await fetch('/foo') // returns { "bar": "baz" }
  
  // ...magic happens here?

  result.frob()                    // logs "frobbed baz" to console
}

Obviously I could make the constructor take the JSON object and pull bar out of it, or write a factory function that does something similar, but I'd rather not have to either call each property out by name, and ideally I'd rather not have to loop over getOwnPropertyNames() or similar either. Is there any way, for instance, that I can just monkey-patch the JSON object to extend Foo?


ETA: Of the answers, Rahul Kumar's Object.setPrototypeOf() is the exact monkey-patch solution I was asking for, but CertainPerformance's Object.assign() is especially useful when you have not just a class, but a complex object with its own state that you don’t want to lose, such as a Vue component.


Solution

  • Use Object.setPrototypeOf() method to set the prototype of result object to the prototype of Foo.

    class Foo {
      constructor(bar) {
        this.bar = bar
      }
      frob() {
        console.log(`frobbed ${this.bar}`);
      }
    }
    
    function frobResult() {
      let result = { bar: "baz" }; // Mock fetch api result
      Object.setPrototypeOf(result, Foo.prototype);
      console.log(result);
      result.frob();
    }
    
    frobResult();