Stackoverflow error on Javascript toJSON custom method
Think it's because toJSON
is semi reserved: stringify
will check the object and see if it's has a method called toJSON
and then try to call it to string the result.
A workaround can be: (Not sure about the reliablity of this code)
var obj = { value: 1, name: "John", toJSON: function() { var ret, fn = this.toJSON; delete this.toJSON; ret = JSON.stringify(this); this.toJSON = fn; return ret; }}
Usage:
obj.toJSON(); // "{\"value\":1,\"name\":\"John\"}"obj.lastName = "Smith";obj.toJSON(); // "{\"value\":1,\"name\":\"John\",\"lastName\":\"Smith\"}"
Maybe using a clousure is a little prettier: (And then I think I can say it's safe)
var obj = { value: 1, name: "John", toJSON: (function() { function fn() { var ret; delete this.toJSON; ret = JSON.stringify(this); this.toJSON = fn; return ret; } return fn; })()}
So after reading @filmor's comment i thoght about another way to handle this. Not that pretty but it works.
Using Function.caller I can detect if fn
is called using JSON.stringify
var obj = { value: 1, name: "John", toJSON: (function() { return function fn() { var ret; delete this.toJSON; ret = JSON.stringify(this); if ( fn.caller === JSON.stringify ) { ret = JSON.parse( ret ); } this.toJSON = fn; return ret; } })()}
Question 1, is toJSON
reserved?
I'm not sure if it reserved, but for example the native Date object uses toJSON to create a stringified date representation:
(new Date()).toJSON(); // -> "2012-10-20T01:58:21.427Z"JSON.stringify({d: new Date()}); // -> {"d":"2012-10-20T01:58:21.427Z"}"
Question 2, an easy solution:
create your custom stringify function that ignores toJSON methods (you may add it to the already existing global JSON
):
JSON.customStringify = function (obj) { var fn = obj.toJSON; obj.toJSON = undefined; var json = JSON.stringify(obj); obj.toJSON = fn; return json;}
now it's very easy to use in all your objects:
function MyObject(id, value, desc){ this.id = id; this.value = value; this.desc = desc; this.toJSON = function() { return JSON.customStringify(this); }}
To make it even more easy additionally add:
JSON.customStringifyMethod = function () { return JSON.customStringify(this);}
Now your objects might look like:
function MyObject(id, value, desc){ this.id = id; this.value = value; this.desc = desc; this.toJSON = JSON.customStringifyMethod;}