Re-associating an object with its class after deserialization in Node.js

class, javascript, json, node.js, serialization

Solution

`Object.create()` and `Object.getOwnPropertyDescriptors()` is what you need.

const obj = JSON.parse(JSON.stringify(d1))
const d3 = Object.create(Dog.prototype, Object.getOwnPropertyDescriptors(obj))

The difference between this and OP's method is that this method sets `prototype` properties on the prototype, whereas OP's method sets properties directly on the object. You can see this when you loop through object own properties using for-in loop with `hasOwnProperty()` method:

for (const i in d1) {
  if (d3.hasOwnProperty(i)) {
    console.log(i)
  }
}

With my method it outputs only `_name`, but with OP's method it outputs also `getName`.

Unfortunately, `Object.getOwnPropertyDescriptors()` is part of ECMAScript 2017 and it's supported only in Firefox for now, so you'll need to use Babel.

Alternatively, you can use `Object.setPrototypeOf()`. It has better browser support than `Object.getOwnPropertyDescriptors()`, but it's discouraged by MDN, because it's slow.

const d3 = JSON.parse(JSON.stringify(d1))
Object.setPrototypeOf(d3, Dog.prototype)

Problem

I'm writing a simple serialization / deserialization framework for some application-specific objects. Consider the following: ``` "use strict"; function Dog(name) { this._name = name; }; Dog.prototype.constructor = Dog; Dog.prototype.getName = function() { return this._name; } var d1 = new Dog('fido'); var d2 = JSON.parse(JSON.stringify(d1)); // serialize / deserialize > d1 Dog { _name: 'fido' } > d1.getName() 'fido' > d2 { _name: 'fido' } > d2.getName() TypeError: d2.getName is not a function ``` At this point, one can ask "What does `d1` have that `d2` lacks?" One approach that partially works is to manually assign the methods of d1 to d2: ``` > d2.constructor = d1.constructor > d2.getName = d1.getName > d2.getName() 'fido' ``` This has a couple of disadvantages. First, I have to manually assign each method of d1 to d2. Second, d2 gets its own properties, and doesn't share slots using the prototype mechanism: ``` > d2 Dog { _name: 'fido', constructor: [Function: Dog], getName: [Function] } ``` So my refined question is: given an object (e.g. `d2`), is there a way to associate it with the prototype of another object (e.g. `d1`) so it inherits the same behavior?

Original source

Related problems