Created
August 16, 2012 21:25
-
-
Save getify/3373779 to your computer and use it in GitHub Desktop.
object JSON serialization that's circular-ref safe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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. | |
// only extend the prototype if `toJSON` isn't yet defined | |
if (!Object.prototype.toJSON) { | |
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 (el instanceof Date || el instanceof Number || el instanceof Boolean || el instanceof String || el instanceof RegExp) { | |
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 (obj instanceof Date || obj instanceof Number || obj instanceof Boolean || obj instanceof String || obj instanceof RegExp) { | |
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; | |
}; | |
// ES5-only: prevent this `toJSON()` from showing up in for-in loops | |
if (Object.defineProperty) { | |
Object.defineProperty(Object.prototype,"toJSON",{enumerable:false}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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":{}} |
@mohsen1 -- in theory, you could certainly do JSON.stringify(window)
, but I just tried it and it gave me a stack overflow error (because my approach uses recursion). The same would probably be true of a DOM object (if it has a bunch of children, especially).
But, moreover, even if it DID work, there's a bunch of stuff you would lose in the transmission. All the functions built onto the window
object for instance would not be transferred. Variables, properties, and other data would make the trip, yes, but what you'd get on the other side is only a shadow of the original window
... definitely not a copy of it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If this works then we would be able to pass
window
or DOM objects to a Web Worker. That would be awesome!