0

JSBin link so that you can run the code quickly.

JSbinhere

The problem is in the comments, but from what the documentation states about how the reviver (that name is terrible), works, if you do not return a value or if you return undefined then that property should be removed from the object. If you return the untransformed value, it stays the same.

Yet when I test it out, it looks like the entire object gets removed. The first example works just fine, the even numbers are converted to their negative and the odd numbers are unchanged.

But in the second example, I don't even get an object back, just undefined. So am I misreading the documentation or is something else wrong?

The result is just undefined in the second example.

    var obj = {
            one: 1,
            innerObj: {
                two: 2,
                four: 4
            },
            two: 2,
            three: 3,
            four: 4
        },
            b = {},
            json = JSON.stringify(obj);
        /**
         *  This works as expected.
         */
        b = JSON.parse(json, function (name, value) {
            if (value % 2 === 0) {
                return -value;
            }
            return value;
        });
        console.log(b);
    /**
    [object Object] {
   four: -4,
   innerObj: [object Object] {
    four: -4,
    two: -2
   },
   one: 1,
   three: 3,
   two: -2
    } 
    */

    obj = {
            one: 1,
            innerObj: {
                two: 2,
                four: 4
            },
            two: 2,
            three: 3,
            four: 4
        };
        b = {};
        json = JSON.stringify(obj);
        /**
         * This does not work as expected, instead of deleting the property on the object, the entire object returns undefined.
         */
        b = JSON.parse(json, function (name, value) {
            if (value % 2 === 0) {
                return -value;
            }

        });
        console.log(b);
// undefined
Michael Ryan Soileau
  • 1,763
  • 17
  • 28

1 Answers1

1

Your second example left return value; off.

But even tough you did that, it should only have removed the properties that returned undefined as value, and I think you found a bug (may be?).

From one of MDN JSON.parse examples it says that last key is "" when JSON.parse is called

I managed to reproduce your code with the undefined error and it seems that if you return the value for the "" key, like

if (name == "") {
  return value;
}

it appears to work as expected.

obj = {
   one: 1,
   innerObj: {
     two: 2,
     four: 4
   },
   two: 2,
   three: 3,
   four: 4
};
b = {};
json = JSON.stringify(obj);


/**
* This does not work as expected, instead of deleting the property on the object, the entire object returns undefined.
*/
b = JSON.parse(json, function (name, value) {
  if (value % 2 === 0) {
    return -value;
  }
  if (name == "") {
    return value;
  }
});
console.log(b);
// { two: -2, four: -4 }

EDIT:

So, reading ECAMScript JSON.parse(text [, reviver]) specification, it seems that this is the expected behavior. When it describes the behavior f calling the reviver function, the last step after calling all DefineOwnProperty items is

Return the result of calling the abstract operation Walk, passing root and the empty String.

So, when you don't return a value for the '' name at your reviver function, it understand that it should remove that, which stands for the whole object to be returned, resulting in it being undefined for the JSON.parse return.

That explains the concern on MDN docs when it says

be certain to return all untransformed values as-is

But I agree that it should be more explicit about how these small nuances work.

Felipe Sabino
  • 17,825
  • 6
  • 78
  • 112
  • I updated my code to check. That now works for the outer object, it returns the two and four from that. But the innerObj is removed entirely still. So it's a partial solution, but I'd expect to keep both sets of data in that case. This is buggy behavior, but I have no idea why. – Michael Ryan Soileau Oct 23 '16 at 21:28
  • but `innerObj` should be removed, as any `object` when applied the `%` operator returns `undefined`. you should type check before applying it using `typeof` and returned `value` when it is not a `number`, for example – Felipe Sabino Oct 24 '16 at 08:24
  • @MichaelRyanSoileau I did some research on ECAMScript's JSON.parse specification and updated my answer. It seems that this is the desired behavior when `undefined` is returned when the `''` is the key for the `reviver` function. – Felipe Sabino Oct 24 '16 at 11:34