使用JSON.stringify()时出现循环原因的TypeError

时间:2013-07-16 08:57:33

标签: javascript json serialization

我有一个JavaScript对象我想序列化为String:

key                     {...}       Object
    mandant             "00001"     String
    personalNummer      600235      Number

首先我使用JSON2,返回值为undefined。使用JSON3我得到TypeErrorjson3.js行中的评论说:

// Cyclic structures cannot be serialized by `JSON.stringify`.

问题似乎来自json3.js中的以下几行:

// Manually invoke the callback for the `constructor` property due to
// cross-environment inconsistencies.
if (isConstructor || isProperty.call(object, (property = "constructor"))) {
    callback(property);
}

但是应该没有循环,我显然无法找出发生了什么。

当我手动创建Object时,调试一切正常。

那么什么可能引起错误?


修改
我成功地准备了一个场景来产生错误:

  • 它恰好发生在IE9中,具有兼容模式IE7和IE8(Firefox 22也很好)
  • 如果打开一个新窗口,它会引用开启窗口中的数据



* JSON_Cycle.html *:

    <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript" src="http://bestiejs.github.io/json3/lib/json3.js"></script>
    <script>
    var dataGlobal = {mandant: "Hallo Welt!", personalNummer: 123456};
        $(function() {
            window.open("JSON_Cycle_Popup.html", 'popup');
        });
    </script>



* JSON_Cycle_Popup.html *:

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript" src="http://bestiejs.github.io/json3/lib/json3.js"></script>
<script>
    var dataGlobal = null;
    $(function() {
        dataGlobal = window.opener.dataGlobal;
        alert(JSON.stringify(dataGlobal));
    });
</script>

2 个答案:

答案 0 :(得分:1)

在序列化之前,我必须设置一个构造函数:

key.constructor = function() {};

修改
但这只适用于对象!使用Array,我遇到了类似的问题。但是这里上面的修复不起作用!

在这种情况下,字符串化实际的数组将在索引0的新数组中打包。有趣的是,实际数组的构造函数仍然是一个函数。但是:索引1和2上还有两个额外的对象,这些对象又是对象。但似乎从JSON lib外部无法操纵。

我没有时间和精力去弄清楚它,或者修改和测试JSON。所以我使用了将元素放入新元素的非常方法(不克隆 - &gt;结果将是同样的错误):

$.each(fahrzeuge, function() {
    zugNummern.push(this);
});

因为只有少数几个元素,它在性能上并不昂贵,而且会做到这一点。但如果有人发布更好的解决方案,我会很高兴。

答案 1 :(得分:1)

根据您问题中的新信息,我现在可以解释发生了什么。

JSON_Cycle.html 文件中,在 dataGlobal 变量初始化后添加以下行。

alert(typeof dataGlobal.constructor);

现在在 JSON_Cycle_Popup.html 中执行相同的操作。请注意区别?在IE上,第一个警报显示构造函数的类型是“函数”,但在弹出窗口中,相同的构造函数返回一种类型的“对象”。

这是第一个问题。下一个问题源于json3枚举对象属性的方式。它们不只是使用常规for循环,即for (property in object) ...。他们有很多代码试图检测不同浏览器实现之间的不一致,以生成一个在所有平台上返回相同结果的枚举器。

这个枚举器的一个效果是,它为每个对象返回一个构造函数属性,即使通常不会在for循环中返回它。这似乎完全没必要,因为你显然不想在json对象中序列化构造函数。但我怀疑这段代码是从其他需要这种行为的项目中继承而来的。

这两个问题的组合意味着在序列化 dataGlobal 对象时,json3将找到它将尝试处理的构造函数属性。然后在序列化构造函数(它认为是另一个对象)时,它将找到另一个构造函数属性(再次看起来像是一个对象)。如果不是下一期,这个过程将继续无限。

在四层构造函数嵌套之后,函数指针循环。即:

dataGlobal.constructor.constructor.constructor.constructor ==
dataGlobal.constructor.constructor

我不知道为什么会这样,但我测试的所有浏览器似乎都是如此。这意味着json3代码不会获得无限递归,而是检测一个循环并抛出TypeError异常。

这就是你错误的解释。 IE中的一个错误与json3属性枚举器的不必要的聪明性相结合。