Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 511
fearless_fool Avatar asked Aug 12 '16 16:08

fearless_fool


People also ask

Can you Stringify a class?

Using .stringify() function on an object, it looks for a toJSON() function on that object and, if such a function exists, stringifies the result of that function's return value. This is super handy, since it allows you to add a toJSON() method to your class and output a plain object for stringifying.

What is deserialize object?

Deserialization is the process of reconstructing a data structure or object from a series of bytes or a string in order to instantiate the object for consumption. This is the reverse process of serialization, i.e., converting a data structure or object into a series of bytes for storage or transmission across devices.

What is serialize and deserialize in JavaScript?

Serialization takes an in-memory data structure and converts it into a series of bytes that can be stored and transferred. Deserialization takes a series of bytes and converts it to an in-memory data structure that can be consumed programmatically.

What is JavaScript deserialize?

The process whereby an object or data structure is translated into a format suitable for transfer over a network, or storage (e.g. in an array buffer or file format). In JavaScript, for example, you can serialize an object to a JSON string by calling the function JSON.


2 Answers

The Best method so far would be:

let obj = Object.assign(new ClassyObject(), JSON.parse(JSON.serialize(the_obj_that_will_lost_prototype)))

Just improved and more direct:

let obj = Object.assign(new the_obj_that_will_lost_prototype.constructor(), JSON.parse(JSON.serialize(the_obj_that_will_lost_prototype)))
like image 149
Newbie Avatar answered Oct 11 '22 10:10

Newbie


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)
like image 38
Michał Perłakowski Avatar answered Oct 11 '22 10:10

Michał Perłakowski