20

For example I have class:

function Test() {
}

Test.prototype = {
    'setTest' : function(test) {
        this.test = test;
    }
}
var test = new Test();
Test.setTest('test');

I want to save object test in database. How to serialize object test to string? (methods, variables, etc)

Max
  • 6,821
  • 3
  • 43
  • 59
Bdfy
  • 23,141
  • 55
  • 131
  • 179

6 Answers6

16

Simple with json

JSON.stringify( test );
Roest
  • 826
  • 6
  • 16
11

In this case, for the question you're asking, there really isn't a way to do what you want. The problem with your request lies in "serializing everything attached to the object, including functions".

Serialization normally only occurs for data, because executables are usually machine bound, in that they are compiled for a given machine, based on certain characteristics. Now, it's reasonable to say that javascript functions just require a javascript interpreter, because javascript is write-once, run-everywhere. But when people write serializers, because all serializers tend to work the same, we write them for data only. In this case, the industry standard is JSON, which is an object-data only serializer.

There are three solutions that avail themselves to you at this point:

  1. Write your own serialier/deserializer that encapsulates functions. This can be tricky, because not all javascript engines will give you access to the source.
  2. Write your own re-loading mechanism that generates a specific new initialized type on each restore, and save the typename as one of the properties on serialization. That way the initialization of each variable gives you the methods, and then merging with the data gives you the complete object.
  3. Store each function as a string and eval it on the fly as you need it. This is incredibly tricky, and is quite prone to errors. I can think of no case where this becomes helpful, because it's quite fragile. However, it is an option, and cannot be overlooked.

I know that 3 is a sub-answer for 1, so you can consider it that there are only two useful answers.

I know that superficially this works on Chrome and IE9, so it should work everywhere the majority of users are likely to use it:

var abc = function(thing) { return thing; }
abc.toString();
// gives "function(thing) { return thing; }" on the command line

So you can certainly serialize the methods as strings in place of the actual method, but you're going to need to create a duplicate object so you can capture every element on the source object (I think, rather than replacing them in place).

Hopefully this helps you think about the problem some more, and maybe to realize you don't need to serialize the methods (nobody ever does that I know of, not reasonably).

jcolebrand
  • 15,889
  • 12
  • 75
  • 121
  • 2
    Closures over context make this harder still: if "thing" was a local var instead of a parameter and abc was returned to an outer scope that doesn't have the thing any more. – bsb May 02 '15 at 21:08
3

The best way to do this is to write your own serialize method which creates a JSON object with attributes, based on your getters. Normally you define a getter per attribute. So it should work for most cases (so you don't have to define a serialize method for each class).

function serialize(obj) {
   var serialized = {};

   for(var prop in obj) {
        if (obj.hasOwnProperty(prop) && typeof obj[prop] == 'function') {
           if (/^get.*/.test(prop)) {
               var value = obj[prop]();
               var name = prop.replace('get', '');

               if (typeof value === 'object') {
                   serialized[name] = this.serialize(value);
                   continue;
               }

               serialized[name] = value;
           }
       }
   }

   return serialized;
};

To reset your attribute values back to the class you have two options:

  • Create a function in your class which creates a valid object instance based on the serialized JSON.
  • Create a unserialize method and map the JSON with your class using the setters.

Example:

function unserialize(obj, emptyClass) {
   // Check emptyClass for setters and map the data from obj to it.
   return 'class instance';
}
Basic Block
  • 729
  • 9
  • 17
Tim
  • 2,236
  • 1
  • 20
  • 26
2

Typically, you'd do this with JSON, which is widely supported across browsers/languages/libraries/etc. The only hangup is that JSON does not support functions – but do you really need to serialize those?

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
0

I've had to support functionality similar to this before. I ended up saving the name of the function as a string and serializing it as JSON. Then when I come back to the client, I execute the function using a helper like the one posted in this question.

If anyone has a better way to solve this problem, I'd want to see it!

Community
  • 1
  • 1
jbabey
  • 45,965
  • 12
  • 71
  • 94
-1

I recently had to find a solution for this problem. I'm sure it can be improved upon.

First I created a module for instantiating the "serialisable" object.

function MyObj(serialised){
    this.val = "";
    if(serialised){
        var unserialised = JSON.parse(serialised);
        for (var i in unserialised) {
            this[i] = unserialised[i];
        }
    }
}

MyObj.prototype.myMethod = function () { return this.val;};

module.exports = MyObj;

you of course have to consider error handling and other validations.

Biso
  • 11
  • 1