Rebinding an object to its class after deserialization in Node.js

I am writing a simple serialization / deserialization structure 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 stage, you can ask the question: "What d1is missing d2?"

One approach that partially works is to manually assign the d1 methods to d2:

> d2.constructor = d1.constructor
> d2.getName = d1.getName
> d2.getName()
'fido'

This has several disadvantages. First, I need to manually assign each method d1 to d2. Secondly, d2 gets its own properties and does not use slots using the prototype mechanism:

> d2
Dog {
   _name: 'fido',
  constructor: [Function: Dog],
  getName: [Function] }

So, my clarified question: an object is asked (for example d2), is there a way to associate it with a prototype of another object (for example d1) so that it inherits the same behavior?

+4
2

Object.create() Object.getOwnPropertyDescriptors() , .

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

OP , prototype , OP . , in-in hasOwnProperty():

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

_name, OP getName.

, Object.getOwnPropertyDescriptors() ECMAScript 2017 Firefox, Babel.


Object.setPrototypeOf(). , Object.getOwnPropertyDescriptors(), MDN, .

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

, , JSON :

Dog.createFromJSON = function(obj) {
  var d = new Dog();
  Object.keys(obj).forEach(function(key) {
    d[key] = obj[key];
  });
  return d;
}

> d3 = Dog.createFromJSON(JSON.parse(JSON.serialize(d1)))
> d3
Dog { _name: 'fido' }
> d3.getName()
'fido'

:

@Louis, @Gothdo , , . , . , , OP:

> var d1 = new Dog('fido');
> d1['_class'] = 'Dog';
> let jsonString = JSON.stringify(d1)
'{"_name":"fido","_class":"Dog"}'

, JSON JAVASCRIPT ( Node.js), , Node.js global:

> global[d1['_class']].prototype
Dog { getName: [Function] }

@Gothdo. :

/**
 * Dynamically create an object from a JSON string of properties.
 * Assumes the presence of a _class meta-property that names the
 * resulting class.
 */
function reconstitute(jsonString) {
    let obj = JSON.parse(jsonString);
    let cls = global[obj['_class']];
    delete obj['_class'];  // remove meta-property
    return Object.setPrototypeOf(obj, cls.prototype);
}

> reconstitute('{"_name":"fido","_class":"Dog"}')
Dog { _name: 'fido' }
+3

Source: https://habr.com/ru/post/1651099/


All Articles