8

How can I use JSON.stringify to convert a negative zero into a string (-0)? It appears that JSON.stringify converts a negative zero into a string representing a positive one. Any idea for a nice workaround?

var jsn = {
    negative: -0
};
isNegative(jsn.negative) ? document.write("negative") : document.write("positive");
var jsonString = JSON.stringify(jsn),
    anotherJSON = JSON.parse(jsonString);
isNegative(anotherJSON.negative) ? document.write("negative") : document.write("positive");

function isNegative(a)
{
    if (0 !== a)
    {
        return !1;
    }
    var b = Object.freeze(
    {
        z: -0
    });
    try
    {
        Object.defineProperty(b, "z",
        {
            value: a
        });
    }
    catch (c)
    {
        return !1;
    }
    return !0;
}
Lukasz Ciastko
  • 381
  • 4
  • 7

2 Answers2

6

You can write a replacer and a reviver function, for JSON.stringify and JSON.parse, respectively. The replacer can utilize that -0 === 0, 1 / 0 === Infinity and 1 / -0 === -Infinity to identify negative zeros and convert them to a special string. The reviver should simply convert the special string back to -0. Here is the jsfiddle.

The code:

function negZeroReplacer(key, value) {
    if (value === 0 && 1 / value < 0) 
        return "NEGATIVE_ZERO";
    return value;
}

function negZeroReviver(key, value) {
    if (value === "NEGATIVE_ZERO")
        return -0;
    return value;
}

var a = { 
        plusZero: 0, 
        minusZero: -0
    },
    s = JSON.stringify(a, negZeroReplacer),
    b = JSON.parse(s, negZeroReviver);

console.clear();
console.log(a, 1 / a.plusZero, 1 / a.minusZero)
console.log(s);
console.log(b, 1 / b.plusZero, 1 / b.minusZero);

Output:

Object {plusZero: 0, minusZero: 0} Infinity -Infinity
{"plusZero":0,"minusZero":"NEGATIVE_ZERO"} 
Object {plusZero: 0, minusZero: 0} Infinity -Infinity

I converted negative zeros to "NEGATIVE_ZERO", but you can use any other string, like "(-0)".

kol
  • 27,881
  • 12
  • 83
  • 120
  • 1
    +1. Had never come across the replacer/reviver functions. Good to know. [Documented here](http://json.org/js.html) – numbers1311407 Oct 24 '13 at 22:08
  • Note that this will mess things up if your object legitimately contains such a string. – SLaks Oct 28 '13 at 13:50
  • @SLaks Sure. That's why I called it a "special" string. It *must* be a string which the objects never contain as a string field. It also *should* indicate that it is a "placeholder" for a negative zero. – kol Oct 28 '13 at 16:43
  • @kol: If your objects can contain user input, no such string exists. Instead, you need an escape mechanism. – SLaks Oct 28 '13 at 16:47
  • @SLaks Interesting. Can you show an example of what it would look like, I mean, the escaping in this special case? – kol Oct 28 '13 at 20:30
  • @kol: You could use `$` as your escape: `$0` maps to `-0`, `$$` maps to `"$"`. Thus, the actual string `$0` would become `$$0`, and the actual string `$$0` would become `$$$$0`. Just like backslash escapes in string literals. – SLaks Oct 28 '13 at 21:25
  • @SLaks I see. The escaping and the unescaping could be done by the replacer and the reviver, respectively. – kol Oct 28 '13 at 22:58
  • If you are using ES6, you can use Object.is to test for -0 instead of the division workaround. I don't know if it will be much faster, but it would certainly be easier to read. – trysis Jan 19 '18 at 20:39
0

you can use JSON.stringify with a replacer function to change out negative zeros to special strings (as stated in the prior answer), and then use a global string replace to change those special strings back to negative zeros in the resulting json string. Ex:

function json(o){
 return JSON.stringify(o,(k,v)=>
  (v==0&&1/v==-Infinity)?"-0.0":v).replace(/"-0.0"/g,'-0')
}

console.log(json({'hello':0,'world':-0}))
Vlad V
  • 109
  • 1
  • 6
  • 1
    While this code may resolve the OP's issue, it is best to include an explanation as to how your code addresses the OP's issue. In this way, future visitors can learn from your post, and apply it to their own code. SO is not a coding service, but a resource for knowledge. Also, high quality, complete answers are more likely to be upvoted. These features, along with the requirement that all posts are self-contained, are some of the strengths of SO as a platform, that differentiates it from forums. You can edit to add additional info &/or to supplement your explanations with source documentation. – ysf Jun 14 '20 at 20:06