48

I need to serialize and deserialize JavaScript objects to store them in a DB.

Note that these objects contain functions, so I can't store them as JSON, so I can't use json2.js.

What's the state of the art in [de]serialization of JavaScript objects (in JavaScript of course).

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Stewart Johnson
  • 14,281
  • 7
  • 61
  • 70
  • 3
    If a javascript object contains functions (i.e.: methods) then there's no way to encode those in JSON. JSON only handles JS objects with pure data (hashes, arrays & primitive types). – Stewart Johnson Aug 31 '10 at 11:40
  • Specifically: I need to store a DirectionsResult object from the Google Maps Javascript API. The DirectionsResult contains LatLng *objects* that have functions that aren't handled by JSON: http://code.google.com/apis/maps/documentation/javascript/reference.html#LatLng – Stewart Johnson Aug 31 '10 at 11:42
  • can't we store function objects as string in json ?? – Viku Mar 29 '15 at 05:45
  • I'd like to serialize objects containing strings to pass them through HTML, allowing all characters. JSON forbids control chars. I don't need to serialize functions. Any short functions for this? – David Spector Jun 04 '21 at 16:36

6 Answers6

34

In general, there's no way (in a browser) to serialize objects with functions attached to them: Every function has a reference to its outer scope, that scope won't exist when you deserialize it, so serialized references to that scope will be invalid.

What I would do is use the built-in (or json2.js) JSON.stringify and JSON.parse functions with the replacer and reviver parameters. Here's a partial example of how it would work:

JSON.stringify(yourObject, function(name, value) {
    if (value instanceof LatLng) { // Could also check the name if you want
        return 'LatLng(' + value.lat() + ',' + value.lng() + ')';
    }
    else if (...) {
        // Some other type that needs custom serialization
    }
    else {
        return value;
    }
});

JSON.parse(jsonString, function(name, value) {
    if (/^LatLng\(/.test(value)) { // Checking the name would be safer
        var match = /LatLng\(([^,]+),([^,]+)\)/.exec(value);
        return new LatLng(match[1], match[2]);
    }
    else if (...) {
        ...
    }
    else {
        return value;
    }
});

You can use any serialization format you want in your custom types. The "LatLng(latitude,longitude)" format is just one way of doing it. You could even return a JavaScript object that can be serialized to JSON natively.

bignose
  • 30,281
  • 14
  • 77
  • 110
Matthew Crumley
  • 101,441
  • 24
  • 103
  • 129
  • Interesting. I read the json2.js docs ("Values that do not have a representation in JSON (such as functions and undefined) are excluded.") and assumed that the replacer/reviver functions aren't called on functions. Is this code you've actually written and used? – Stewart Johnson Sep 01 '10 at 04:51
  • @Stewart: The idea is that you avoid having to serialize the functions by re-constructing the objects when you deserialize them. The `LatLng` constructor will add the functions back in for you. The replacer will work on functions though, so if you really want to, you could try converting the function to a string. Just be aware that it won't work in every case. – Matthew Crumley Sep 01 '10 at 05:43
  • Doesn't handle certain characters, like newline, in strings. – David Spector Jun 04 '21 at 16:32
9

You don't want to serialize logic such as functions.

If you have to update your logic / js functions in the future, you don't (always) want the older logic to be loaded back with the data neccessarily. Beware.

lknox
  • 109
  • 1
  • 2
7

use gserializer:

http://www.onegeek.com.au/articles/programming/javascript-serialization.php

the code in google :

http://code.google.com/p/gserializer/

GSerializer is a javascript library to serialize/deserialize javascript objects to and from strings, for persistance in say, a Cookie. Unlike many other implementations, GSerializer can also serialize functions and non-JSON notation.

Haim Evgi
  • 123,187
  • 45
  • 217
  • 223
  • I came across that earlier but I wasn't sure about the project's maturity. Have you used it personally? – Stewart Johnson Aug 31 '10 at 11:39
  • 4
    Looks like it won't work: Gserializer TODO says: "Implement passing parameters into serialized functions (currently only supports no-argument functions)", and the objects I've got to serialize contain functions with arguments (toUrlValue function on LatLng object: http://code.google.com/apis/maps/documentation/javascript/reference.html#LatLng). Thanks anyway! – Stewart Johnson Aug 31 '10 at 11:56
  • sorry 2, i hope they finish this project – Haim Evgi Aug 31 '10 at 11:58
  • He hasn't touched the project in a year. Too bad. I also need functions with arguments – huyz Aug 22 '11 at 15:59
2

On Node.js, there is also the JASON package.

Here is the example:

var JASON = require("JASON");

str = JASON.stringify(obj);
obj = JASON.parse(str);

Install the package by: npm install JASON.

kenorb
  • 155,785
  • 88
  • 678
  • 743
prototype
  • 7,249
  • 15
  • 60
  • 94
1

If you're using ES6 versions of Node, you can check out a small package I wrote called JSOFF. It's the JavaScript Object-Function Format; a drop-in replacement for JSON that handles functions.

It's super tiny and simple, so Babeljs or Browserify may be your friends.

Install via: npm install jsoff or yarn add jsoff.

Here is the example how to create an object with functions:

const JSOFF  = require('jsoff');

var obj = {
  abc: 123,
  def: function (a,b) { return a * 2 + b * 3; },
  ghi: a => { return a * 2 },
  jkl: (a,b) => { return ((d,e) => { return a*d + b*e })(2,4) }
};

var str = JSOFF.stringify(obj);
// str is now:  
// '{"abc":123,"def":"function (a,b) { return a * 2 + b * 3; }","ghi":"a => { return a * 2 }","jkl":"(a,b) => { return ((d,e) => { return a*d + b*e })(2,4) }"}');
});

var clone = JSOFF.parse(str);
clone.def(10,5)   // 35
clone.ghi(5)      // 10
clone.jkl(10,20)  // 100
kenorb
  • 155,785
  • 88
  • 678
  • 743
Sir Robert
  • 4,686
  • 7
  • 41
  • 57
0

I wouldn't serialize JS functions because of security reasons. Through a public API all kinds of nasty things could be sent to the database. As for deserialisation I've got a different approach. I'm mixing model objects defined on client side with the data coming from JSON. I have a small tool to do that, take a look at it on GitHub at khayll/jsonmix.

JsonMix provides a kind of deserialisation from JSON into JavaScript Objects complete with functions.

It would look like something:

//model definition (just an example)

var LatLng = function() {}
LatLng.prototype.getMapTypeId = function() {
   return this.mapTypeId;
}

//deserializing done like this
var result = JSMix(jsonString).withObject(LatLng.prototype, "latLngs").build();

//all items in the latLngs collection have the functions coming from the model
console.log(result.latLngs[5].getMapTypeId());
kenorb
  • 155,785
  • 88
  • 678
  • 743
fishgen
  • 71
  • 3
  • 2
    Can you clarify why **serialising** Javascript functions could under any circumstance be a security risk? – Codebling Oct 11 '16 at 01:47
  • 1
    if you have a public API, that accepts a serialised javascript object including functionality, and this is used in a web application. then malicious code can be sent to your server. Suppose you also read these objects back somewhere in your web application and use them. Now if someone overrides the toString() function on that object, and you happen to use it in your code, than that someone could alter the intended functionality of the web application. So while you downloaded it from a secure url, the functionality can no longer be trusted. – fishgen Apr 25 '17 at 01:24
  • 1
    Of course. But it's the accepting by the server and the subsequent deserialisation and use of code that is the risk. Serialising itself is not dangerous. – Codebling May 11 '17 at 07:38
  • @fishgen Code Bling is right. What's more, there's no need to assume his use case or intended purpose for serialization is yours. His purpose could be, for example, archival for compliance purposes; research oriented; or any number of other purposes. – Sir Robert Jul 15 '17 at 00:43