7

Let's say I have a fairly nested JS object like this and I need to JSON-encode it:

var foo = { 
    "totA": -1,
    "totB": -1,
    "totC": "13,052.00",
    "totHours": 154,
    "groups": [
        {"id": 1,
        "name": "Name A",
        "billingCodes": [
            {"bc": "25", "type": "hours", "hours": "5", "amount": "$25.00"}
        ]}
    ] 
};

If I JSON-encode it using the native browser JSON.stringify (tested in Chrome, Firefox, IE9/10), I get back a JSON string that looks like this (which is what I expect):

Native JSON.stringify JSFiddle example

{
    "totA": -1,
    "totB": -1,
    "totC": "13,052.00",
    "totHours": 154,
    "groups": [
        {
            "id": 1,
            "name": "Name A",
            "billingCodes": [
                {
                    "bc": "25",
                    "type": "hours",
                    "hours": "5",
                    "amount": "$25.00"
                }
            ]
        }
    ]
}

The weirdness comes in if I try to do the same thing on a page that's using either PrototypeJS or json2.js.

In that case, JSON.stringify on the same object gives me back the following JSON:

ProtypeJS JSON.stringify JSFiddle example

{
    "totA": -1,
    "totB": -1,
    "totC": "13,052.00",
    "totHours": 154,
    "groups": "[{\"id\": 1, \"name\": \"Name A\", \"billingCodes\": [{\"bc\": \"25\", \"type\": \"hours\", \"hours\": \"5\", \"amount\": \"$25.00\"}]}]"
}

Obviously, the above is a problem because it doesn't JSON-decode to the same object that was originally passed to JSON.stringify.

Can anyone elaborate on what's going on and why there's this difference?

What am I missing?

Mark Biek
  • 146,731
  • 54
  • 156
  • 201
  • Looks like it might be a bug, changing the Fiddle to use Prototype 1.7.1 seems to produce the expected results. See this : https://github.com/bestiejs/json3/issues/8 – HBP Jul 12 '13 at 15:51
  • Looks like it just JSON encoded the whole `groups` array. – Derek 朕會功夫 Jul 12 '13 at 15:51
  • 2
    Duplicate? http://stackoverflow.com/questions/710586/json-stringify-bizarreness ... From an answer on that question, `delete Array.prototype.toJSON` –  Jul 12 '13 at 15:52
  • 1
    Yup, definitely a dupe. Thanks @crazy-train – Mark Biek Jul 12 '13 at 16:31

1 Answers1

7

This is because native JSON.stringify respects toJSON methods, and Prototype adds these all over the place. Unfortunately, native and Prototype appear to understand toJSON in different ways: while native expects it to return a string, which is used as a literal value, Prototype's toJSON returns chunks of already formatted JSON which are meant to be used as is. Hence the discrepancy.

This works fine:

delete Array.prototype.toJSON;
document.getElementById('out').innerHTML += JSON.stringify(foo);

http://jsfiddle.net/Ky3tv/2/

Also, this appears to be fixed in Prototype 1.7. I guess they're now checking for native JSON before adding their toJSON methods.

georg
  • 211,518
  • 52
  • 313
  • 390