Sign up ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free.

I've got a javascript object definition which contains a circular reference: it has a property that references the parent object.

It also has functions that I don't want to be passed through to the server. How would I serialize and deserialize these objects?

I've read that the best method to do this is to use Douglas Crockford's stringify. However, I'm getting an uncaught exception circular reference in chrome.

function finger(xid, xparent){
    this.id = xid;
    this.xparent;
    //other attributes
}

function arm(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.fingers = [];

    //other attributes

    this.moveArm = function() {
        //moveArm function details - not included in this testcase
        alert("moveArm Executed");
    }
}

 function person(xid, xparent, xname){
    this.id = xid;
    this.parent = xparent;
    this.name = xname
    this.arms = []

    this.createArms = function () {
        this.arms[this.arms.length] = new arm(this.id, this);
    }
}

function group(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.people = [];
    that = this;

    this.createPerson = function () {
        this.people[this.people.length] = new person(this.people.length, this, "someName");
        //other commands
    }

    this.saveGroup = function () {
        alert(JSON.stringify(that.people));
    }
}

This is a testcase that I created for this question. There are errors within this code but essentially I have objects within objects, and a reference passed to each object to show what the parent object is when the object is created. Each object also contains functions, which I don't want stringified. I just want the properties such as the Person.Name.

How do I serialize before sending to the server and deserialize it assuming that the same json is passed back.

Also, please note that I'm using jquery as my is library.

share|improve this question
3  
Hi, I didn't realize I had to accept answers. I'll update this. –  user1012500 May 1 '12 at 3:12

4 Answers 4

up vote 33 down vote accepted

Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a) or indirectly (a -> b -> a).

To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference. For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:

JSON.stringify( that.person, function( key, value) {
  if( key == 'parent') { return value.id;}
  else {return value;}
}

The second parameter to stringify is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.

You can test the above code with the following:

function Person( params) {
  this.id = params['id'];
  this.name = params['name']; 
  this.father = null;
  this.fingers = [];
  // etc.
}

var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him; 
JSON.stringify(me); // so far so good

him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
  if(key == 'father') { 
    return value.id;
  } else {
    return value;
  };
});

BTW, I'd choose a different attribute name to "parent" since it is a reserved word in many languages (and in DOM). This tends to cause confusion down the road...

share|improve this answer

I used the following to eliminate the circular references:

JS.dropClasses = function(o) {

    for (var p in o) {
        if (o[p] instanceof jQuery || o[p] instanceof HTMLElement) {
            o[p] = null;
        }    
        else if (typeof o[p] == 'object' )
            JS.dropClasses(o[p]);
    }
};

JSON.stringify(JS.dropClasses(e));
share|improve this answer

I found two suitable modules to handle circular references in JSON.

  1. CircularJSON https://github.com/WebReflection/circular-json whose output can be used as input to .parse(). It also works in Browsers & Node.js Also see: http://webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
  2. Isaacs json-stringify-safe https://github.com/isaacs/json-stringify-safe which maybe more readable but can't be used for .parse and is only available for Node.js

Either of these should meet your needs.

share|improve this answer

It appears that dojo can represent circular references in JSON in the form : {"id":"1","me":{"$ref":"1"}}

Here is an example:

http://jsfiddle.net/dumeG/

require(["dojox/json/ref"], function(){
    var me = {
        name:"Kris",
        father:{name:"Bill"},
        mother:{name:"Karen"}
    };
    me.father.wife = me.mother;
    var jsonMe = dojox.json.ref.toJson(me); // serialize me
    alert(jsonMe);
});​

Produces:

{
   "name":"Kris",
   "father":{
     "name":"Bill",
     "wife":{
          "name":"Karen"
      }
   },
   "mother":{
     "$ref":"#father.wife"
   }
}

Note: You can also de-serialize these circular referenced objects using the dojox.json.ref.fromJson method.

Other Resources:

How to serialize DOM node to JSON?

JSON.stringify can't represent circular references

share|improve this answer
    
Hi, thanks for your answer. I should have stated that I'm using jquery as my is library. I didn't think it was relevant at the time.ill update my post. –  user1012500 May 1 '12 at 3:25
    
@user1012500 - Dojo works fine alongside jQuery. I often include other libraries or frameworks to compensate for deficiencies in my primary framework. You may even be able to extract the toJson and fromJson methods and create your own jQuery wrapper around them. That way you won't need to pull in the whole framework. Unfortunately, jQuery does not have this functionality out of the box, and JSON.stringify can't handle these types of objects. So other than the above examples, you may have to code this functionality yourself. –  Brandon Boone May 1 '12 at 11:44
    
Hi Brandon, I'm hesitant to add another library to solve the problem since it adds another footprint to the site. However, i gave dojo a shot and attempted to use your example against mine. However, i ran into the circular reference issue (I don't have much knowledge of dojo, so I've just attempted a couple of things but mainly based on your example): jsfiddle.net/Af3d6/1 –  user1012500 May 1 '12 at 22:00
    
JSON not to be confused with JavaScript object literals cannot contain functions since it is a data interchange format (like XML). So in order to serialize to the JSON format, you need a compliant object literal. This example modifies your example to be compliant (though it may not be what your looking for since you're no longer working with object instances). Even when you remove your toJSON functions, the references to the underlying prototype functions still makes it invalid. –  Brandon Boone May 2 '12 at 1:22
    
Hi, In the end I had to go it alone and customise my stringify calls. thanks anyway. –  user1012500 May 27 '12 at 10:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.