Stackoverflow error on Javascript toJSON custom method Stackoverflow error on Javascript toJSON custom method json json

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;}