Skip to content

Instantly share code, notes, and snippets.

@NHQ
Forked from getify/test.js
Created August 18, 2012 07:58
Show Gist options
  • Save NHQ/3385135 to your computer and use it in GitHub Desktop.
Save NHQ/3385135 to your computer and use it in GitHub Desktop.
object JSON serialization that's circular-ref safe
// all this `toJSON()` does is filter out any circular refs. all other values/refs,
// it passes through untouched, so it should be totally safe. see the test examples.
Object.prototype.toJSON = function() {
function findCircularRef(obj) {
for (var i=0; i<refs.length; i++) {
if (refs[i] === obj) return true;
}
return false;
}
function traverse(obj) {
function element(el) {
if (typeof el === "object") {
if (el !== null) {
if (Date === el.constructor || Number === el.constructor || Boolean === el.constructor || String === el.constructor || RegExp === el.constructor) {
return el;
}
else if (!findCircularRef(el)) {
return traverse(el);
}
}
return null;
}
return el;
}
var idx, tmp, tmp2;
if (Object.prototype.toString.call(obj) === "[object Array]") {
refs.push(obj);
tmp = [];
for (idx=0; idx<obj.length; idx++) {
tmp.push(element(obj[idx]));
}
refs.pop();
return tmp;
}
else if (typeof obj === "object") {
if (obj !== null) {
if (Date === obj.constructor || Number === obj.constructor || String === obj.constructor || Boolean === obj.constructor || RegExp === obj.constructor) {
return obj;
}
else if (!findCircularRef(obj)) {
refs.push(obj);
tmp = {};
for (idx in obj) { if (obj.hasOwnProperty(idx)) {
tmp2 = element(obj[idx]);
if (tmp2 !== null) tmp[idx] = tmp2;
}}
refs.pop();
return tmp;
}
}
return null;
}
else return obj;
}
var refs = [], ret;
ret = traverse(this);
refs = [];
return ret;
};
var a = {
b: 12,
c: true,
d: "foobar",
e: {
f: function() { alert("blah"); }, // functions get ignored
g: new Date(), // dates get their own `toJSON()` serialization called
h: [ true,1.3,"haha" ]
},
k: {},
l: /foobar/g // regexes get turned into an empty {}
};
a.i = a; // circular ref!!
a.e.i = a; // circular ref!!
a.e.j = a.e; // circular ref!!
a.e.h.push(a.e); // circular ref!! since it's in array, will be replaced with `null`
a.k.m = a.e; // **NOT** a circular ref, just a dupe ref, so leave it alone!!
// Look Ma! No circular refs!
JSON.stringify(a); // {"b":12,"c":true,"d":"foobar","e":{"g":"2012-08-17T12:11:05.647Z","h":[true,1.3,"haha",null]},"k":{"m":{"g":"2012-08-17T12:11:05.647Z","h":[true,1.3,"haha",null]}},"l":{}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment