Jan 23 2010
∞
JSON.stringify bug with Native FF Implementation
Firefox past 3.5.4 natively implements JSON.stringify with replacers, similarly to the way JSON2 works. However, it’s doing something wrong (optimization related?). Supposedly, you can pass stringify a replacer function as a second argument and it will use whatever is returned from that argument as the value in the serialized copy. HOWEVER, if you pass a value back that contains the same values (but is not === to) the original value, the JSON.stringify uses the original value instead. This sucks for me, because I want to pass back an array with the toJSON method wiped, without destroying the (incorrectly implemented by Prototype) toJSON method on the original. Here’s a jasmine spec:
function json2PrototypeFix(key, value) {
if (typeof this[key] == 'object' && Object.prototype.toString.apply(this[key]) === '[object Array]') {
var copy = this[key].slice(0);
this[key] = [1];
return copy;
} else {
return value
}
}
describe('JSON with protoype', function () {
it('should properly stringify an object with child arrays', function() {
var array = [1,2];
var obj = {"foo": array};
var result = JSON.stringify(obj, json2PrototypeFix);
expect(result).toEqual("{\"foo\":[1,2]}");
});
});
The failure I get here is
Expected '{"foo":"[1]"}' to equal '{"foo":[1,2]}'.
which implies I’m using the original value, even though I passed back the copy I made of it.
If I allow Crockford’s original JSON2 to overwrite the stringify function, then everything works as expected.
This is super frustrating — both Prototype AND Firefox are broken in this case, so I can’t reliably fix the parts of Jasmine that need JSON.stringify to work correctly when Prototype is present. I think I’m just going to check for the presence of prototype and then just use their toJSON, instead of fixing the issue using JSON2’s replacer support (which isn’t going to be present everywhere anyways — sounds like it’ll break in browsers that implement JSON.stringify without the replacer arg; ie FF