【问题标题】:Unexpected behavior in JSON.parse Reviver function, deleting the object and not the key propertiesJSON.parse Reviver 函数中的意外行为,删除对象而不是关键属性
【发布时间】:2017-03-05 14:08:18
【问题描述】:

JSBin 链接,方便你快速运行代码。

JSbinhere

问题出在 cmets 中,但是从文档中关于 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

【问题讨论】:

    标签: javascript json reviver-function


    【解决方案1】:

    您的第二个示例关闭了return value;

    但即使你这样做很难,它应该只删除返回 undefined 作为值的属性,我认为你发现了一个错误(可能是?)。

    MDN JSON.parse examples 之一说,当调用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]) specification,这似乎是预期的行为。当它描述调用reviver函数的行为时,调用所有DefineOwnProperty项后的最后一步是

    返回调用抽象操作Walk的结果,传入root和空字符串。

    因此,当您没有在 reviver 函数中返回 '' 名称的值时,它知道它应该删除它,这代表要返回的整个对象,导致它是 undefined 用于JSON.parse 返回。

    这解释了对 MDN 文档的担忧

    确保按原样返回所有未转换的值

    但我同意应该更明确地说明这些细微差别是如何工作的。

    【讨论】:

    • 我更新了我的代码以进行检查。这现在适用于外部对象,它从中返回二和四。但是 innerObj 仍然被完全删除。所以这是一个部分解决方案,但我希望在这种情况下保留两组数据。这是错误的行为,但我不知道为什么。
    • 但应该删除innerObj,因为任何object 在应用% 运算符时都会返回undefined。您应该在使用typeof 应用它之前键入检查,并在它不是number 时返回value,例如
    • @MichaelRyanSoileau 我对 ECAMScript 的 JSON.parse 规范做了一些研究并更新了我的答案。当''reviver 函数的键时,这似乎是返回undefined 时所需的行为。
    猜你喜欢
    • 2018-04-02
    • 2012-12-27
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 2017-05-03
    • 2018-02-03
    相关资源
    最近更新 更多