Неожиданное поведение в функции восстановления JSON.parse, удаление объекта, а не свойств ключа

#javascript #json #reviver-function

#javascript #json #reviver-функция

Вопрос:

Ссылка на JSBin, чтобы вы могли быстро запустить код.

JSbinhere

Проблема в комментариях, но из того, что говорится в документации о том, как работает reviver (это ужасное название), если вы не возвращаете значение или если вы возвращаете undefined , то это свойство должно быть удалено из объекта. Если вы возвращаете нетрансформированное значение, оно остается прежним.

Тем не менее, когда я это тестирую, похоже, что удаляется весь объект. Первый пример работает просто отлично, четные числа преобразуются в отрицательные, а нечетные числа остаются неизменными.

Но во втором примере я даже не получаю объект обратно, просто неопределенный. Итак, я неправильно читаю документацию или что-то еще не так?

Результат просто не определен во втором примере.

     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
  

Ответ №1:

Ваш второй пример не приведен return value; .

Но даже если вы это сделали, это должно было удалить только свойства, которые возвращались undefined как значение, и я думаю, вы нашли ошибку (может быть?).

В одном из MDN JSON.parse примеров говорится, что последний ключ — это "" когда JSON.parse вызывается

Мне удалось воспроизвести ваш код с undefined ошибкой, и кажется, что если вы вернете значение для "" ключа, например

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

похоже, что это работает так, как ожидалось.

 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 }
  

Редактировать:

Итак, читая спецификацию ECAMScript JSON.parse(text [, reviver]), кажется, что это ожидаемое поведение. Когда описывается поведение при вызове reviver функции, последним шагом после вызова всех DefineOwnProperty элементов является

Возвращает результат вызова абстрактной операции Walk, передавая root и пустую строку.

Итак, когда вы не возвращаете значение для '' имени в вашей функции reviver, она понимает, что она должна удалить это, что означает, что весь объект должен быть возвращен, в результате чего он будет undefined для JSON.parse возврата.

Это объясняет озабоченность в документах MDN, когда говорится

обязательно возвращайте все нетрансформированные значения как есть

Но я согласен, что следует более подробно рассказать о том, как работают эти небольшие нюансы.

Комментарии:

1. Я обновил свой код для проверки. Теперь это работает для внешнего объекта, он возвращает двойку и четыре из этого. Но innerObj по-прежнему полностью удаляется. Итак, это частичное решение, но я бы ожидал сохранить оба набора данных в этом случае. Это некорректное поведение, но я понятия не имею, почему.

2. но innerObj должен быть удален, так как любой object при применении % оператор возвращает undefined . вы должны ввести check перед его применением, используя typeof и возвращаемый value , когда это не number , например

3. @MichaelRyanSoileau Я провел некоторое исследование спецификации JSON.parse ECAMScript и обновил свой ответ. Кажется, что это желаемое поведение, когда undefined возвращается, когда '' является ключом для reviver функции.