Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding "toJSON" method a JavaScript object instance causes Maximum Callstack error

I wanted to add a .toJson method to an instantiated JavaScript object, which would allow me to get the stringified object instance without functions and prototype, to transmit during a request.

However, it seems like the actual name of the function 'toJSON' as a method name impacts the ability of JavaScript engine (at least in V8) to run the function - that is, if you rename the same exact function to "JSON" instead of "toJSON", it works, however, as "toJSON", it causes a Maximum Callstack error. See example:

function P1(name, age){
    this.name = name;
    this.age= age;
    this.toJSON = function(){
        return JSON.stringify(this);
    }
}

function P2(name, age){
    this.name = name;
    this.age= age;
    this.JSON = function(){
        return JSON.stringify(this);
    }
}

// This causes an error: Uncaught RangeError: Maximum call stack size exceeded(…)
var p1 = new P1('Memory Error', 10);
try {
  p1.toJSON();
} catch(e){
    console.log(e);
}

var p2 = new P2('No Error', 20);
p2.JSON();

Is this an expected behavior of JavaScript? Does it have something to do with "toJSON" being a native method (note: I have verified that on an instantiated object as above, there is no toJSON method on the prototype that would interfere with a redefinition on the instance)? I am trying to determine if I should report this as a bug to V8 team, or this is explainable by someone who knows more about the spec.

Thanks

like image 289
netpoetica Avatar asked Dec 15 '22 11:12

netpoetica


1 Answers

This is not what the .toJSON method is used for. You use .toJSON to override the default stringification behavior. The .toJSON is called internally by JSON.stringify, you don't need to call it on your own. .toJSON can return a string, object, array, whatever you want to be stringified in the response from JSON.stringify.

Your .toJSON method needs to do something other than call JSON.stringify(this). Right now you are getting an infinite loop since JSON.stringify(this) calls the object's .toJSON, and so on.

Try something like this:

function P1(name, age){
    this.name = name;
    this.age= age;
    this.toJSON = function(){
        return {
            name: this.name,
            age: this.age
        };
    }
}

var p1 = new P1('Test', 10);
console.log(JSON.stringify(p1));
like image 175
Rocket Hazmat Avatar answered Dec 16 '22 23:12

Rocket Hazmat