JSON.stringify() array bizarreness with Prototype.js

84,841

Solution 1

Since JSON.stringify has been shipping with some browsers lately, I would suggest using it instead of Prototype’s toJSON. You would then check for window.JSON && window.JSON.stringify and only include the json.org library otherwise (via document.createElement('script')…). To resolve the incompatibilities, use:

if(window.Prototype) {
    delete Object.prototype.toJSON;
    delete Array.prototype.toJSON;
    delete Hash.prototype.toJSON;
    delete String.prototype.toJSON;
}

Solution 2

The function JSON.stringify() defined in ECMAScript 5 and above (Page 201 - the JSON Object, pseudo-code Page 205), uses the function toJSON() when available on objects.

Because Prototype.js (or another library that you are using) defines an Array.prototype.toJSON() function, arrays are first converted to strings using Array.prototype.toJSON() then string quoted by JSON.stringify(), hence the incorrect extra quotes around the arrays.

The solution is therefore straight-forward and trivial (this is a simplified version of Raphael Schweikert's answer):

delete Array.prototype.toJSON

This produces of course side effects on libraries that rely on a toJSON() function property for arrays. But I find this a minor inconvenience considering the incompatibility with ECMAScript 5.

It must be noted that the JSON Object defined in ECMAScript 5 is efficiently implemented in modern browsers and therefore the best solution is to conform to the standard and modify existing libraries.

Solution 3

A possible solution which will not affect other Prototype dependencies would be:

var _json_stringify = JSON.stringify;
JSON.stringify = function(value) {
    var _array_tojson = Array.prototype.toJSON;
    delete Array.prototype.toJSON;
    var r=_json_stringify(value);
    Array.prototype.toJSON = _array_tojson;
    return r;
};

This takes care of the Array toJSON incompatibility with JSON.stringify and also retains toJSON functionality as other Prototype libraries may depend on it.

Solution 4

Edit to make a bit more accurate:

The problem key bit of code is in the JSON library from JSON.org (and other implementations of ECMAScript 5's JSON object):

if (value && typeof value === 'object' &&
  typeof value.toJSON === 'function') {
  value = value.toJSON(key);
}

The problem is that the Prototype library extends Array to include a toJSON method, which the JSON object will call in the code above. When the JSON object hits the array value it calls toJSON on the array which is defined in Prototype, and that method returns a string version of the array. Hence, the quotes around the array brackets.

If you delete toJSON from the Array object the JSON library should work properly. Or, just use the JSON library.

Solution 5

This is the code I used for the same issue:

function stringify(object){
      var Prototype = window.Prototype
      if (Prototype && Prototype.Version < '1.7' &&
          Array.prototype.toJSON && Object.toJSON){
              return Object.toJSON(object)
      }
      return JSON.stringify(object)
}

You check if Prototype exists, then you check the version. If old version use Object.toJSON (if is defined) in all other cases fallback to JSON.stringify()

Share:
84,841
morgancodes
Author by

morgancodes

Programmer/artist working on a monster javascript project for a cable television company for the past two and a half years. Meanwhile, I build magical sound experiences for iOS including Thicket, Morton Subotnick's Pitch Painter, and this fun toy payed for by gum. I also like to make geometric sculptures from paper. Future plans include releasing my C++ audio patching engine (build on top of STK) as an open source project, creating the world's most mesmerizing musical video game, building my own programming language, and finding a way to pay for it all.

Updated on July 16, 2022

Comments

  • morgancodes
    morgancodes almost 2 years

    I'm trying to figure out what's gone wrong with my json serializing, have the current version of my app with and old one and am finding some surprising differences in the way JSON.stringify() works (Using the JSON library from json.org).

    In the old version of my app:

     JSON.stringify({"a":[1,2]})
    

    gives me this;

    "{\"a\":[1,2]}"
    

    in the new version,

     JSON.stringify({"a":[1,2]})
    

    gives me this;

    "{\"a\":\"[1, 2]\"}"
    

    any idea what could have changed to make the same library put quotes around the array brackets in the new version?