TL; DR:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析包含数组的任何JSON时获得堆栈溢出,但仅限于你还将一个reviver函数传递给JSON.parse()。
这开始是一个问题,但我回答了我自己的原始问题,所以现在我会问:任何人都可以想到解决这个IE8错误的解决办法,不涉及删除所有修改数组的JS库。 prototype和Function.prototype?
原始问题:
我要解析大约13k的JSON数据。数据的结构是一个具有单个值的对象,该值是嵌套数组。
{ 'value':[[ stuff ], [ more stuff], [ etc ]] }
我正在使用json2.js,它在可用时遵循浏览器本机JSON.parse。我正在将一个reviver函数传递给JSON.parse来正确处理日期。当IE8处于IE7仿真模式(导致它使用基于脚本的json2.js解析器)时,一切正常。当IE8处于IE8模式(导致它使用浏览器本机JSON解析器)时,它会出现“堆栈空间不足”错误。当然,Firefox和Chrome可以与浏览器原生的JSON解析器一起使用。
我已将其缩小到这一点:如果我将一个do-nothing reviver函数传递给JSON.parse,IE8本机解析器会获得堆栈溢出。如果我没有传递reviver函数,IE8本机解析器工作正常,除了它不能正确解析日期。
// no error:
JSON.parse(stuff);
// "out of stack space" error:
JSON.parse(stuff, function(key, val) { return val; });
我将使用我的JSON数据,看看数据的减少或数据的嵌套是否可以避免错误,但我想知道是否有人之前已经看过这个,或者有任何其他建议的解决方法。 IE8已经足够慢了,因为这个错误而禁用该浏览器的原生JSON将是一种耻辱。
更新:在其他情况下,使用不同的JSON数据,当我使用具有reviver功能的IE8本机解析器时,我收到javascript错误“$ lineinfo is undefined”,如果我不使用reviver函数则没有错误。字符串“$ lineinfo”不会出现在我的任何源代码中。
更新2:实际上,这个问题似乎是由原型1.6.0.3引起的。在我添加到Prototype库中之前,我无法在隔离的测试页中重现它。
更新3:
prototype.js打破IE8原生JSON解析器的原因是:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析任何JSON时获得堆栈溢出包含一个数组,但只有当你还将一个reviver函数传递给JSON.parse()。
Prototype库为Array.prototype和Function.prototype添加了函数,但这同样适用于执行相同操作的任何其他库。 IE JSON解析器中的这个错误由Prototype和Ext公开,但不是jQuery。我还没有测试过任何其他框架。
这是一个完全独立的问题再现。如果删除Function.prototype行或Array.prototype行,或从JSON字符串中删除该数组,则不会出现“堆栈空间不足”错误。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
Function.prototype.test1 = function() { };
Array.prototype.test2 = function() { };
window.onload = function()
{
alert(JSON.parse('{ "foo": [1,2,3] }', function(k,v) { return v; }));
}
</script>
</head>
<body>
</body>
</html>
答案 0 :(得分:6)
这只是补丁。 http://support.microsoft.com/kb/976662
http://msdn.microsoft.com/en-us/library/cc836466(VS.85).aspx
答案 1 :(得分:5)
解决方案是删除IE8上的本机JSON.parse并将其替换为json2.js lib中的JSON.parse:
添加:
<script type="text/javascript">
if (jQuery.browser.msie && jQuery.browser.version.indexOf("8.") === 0) {
if (typeof JSON !== 'undefined') {
JSON.parse = null;
}
}
<script>
...然后包括:
<script type="text/javascript" src="json2.js"></script>
这将触发json2将JSON.parse替换为自己的版本
// json2.js
...
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
...
之后解析应该再次起作用。
这种方法的一个问题是json2.js解析方法比原生方法慢。
答案 2 :(得分:3)
我已经有了这个问题,并且没有可接受的答案,但是为了摆脱它,我会自己回答。
微软的Eric Law说:JavaScript小组报告这是JavaScript引擎中的一个已知问题。
答案 3 :(得分:2)
这似乎工作正常:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Test</title>
</head>
<body>
<pre>
<script type="text/javascript">
document.writeln('');
var o = {
"firstName": "cyra",
"lastName": "richardson",
"address": {
"streetAddress": "1 Microsoft way",
"city": "Redmond",
"state": "WA",
"postalCode": 98052
},
"phoneNumbers": [
"425-777-7777",
"206-777-7777"
]
};
var s = JSON.stringify(o);
document.writeln(s);
var p = JSON.parse(s, function (key, val) {
if (typeof val === 'string') return val + '-reviver!';
else return val;
});
dump(p);
function dump(o) {
for (var a in o) {
if (typeof o[a] === 'object') {
document.writeln(a + ':');
dump(o[a]);
} else {
document.writeln(a + ' = ' + o[a]);
}
}
}
</script>
</pre>
</body>
</html>
问题是Internet Explorer 8安装损坏(您是否尝试在同一Windows安装上运行Internet Explorer的多个副本?)或输入错误。
您可能还想阅读Native JSON in IE8。可能会对此特定段落感兴趣:
可选的 revive参数是一个用户 用于post parse的定义函数 变化。生成的对象或数组 递归遍历, reviver 功能适用于每个成员。 每个成员值都替换为 reviver 返回的值。如果 reviver返回null,即对象 会员被删除。遍历和 关于复活的呼吁是在 后序。那就对了;每个对象 在所有成员之后'复活' “恢复“。
上面的段落解释了为什么我的reviver功能看起来像它的方式。我对测试代码的第一次尝试是:
function (key, val) {
return val + '-reviver!';
}
显然,如果将 reviver 函数应用于上面的address
节点后应用于其所有子节点,我就完全销毁了address
对象。
当然,如果 reviver 的测试与您在问题中描述的一样简单,那么某些全局循环引用不太可能导致您遇到的问题。我仍然认为它指向Internet Explorer损坏或数据不良。
你可以edit your question发布一个展示问题的实际数据样本,以便我可以在这里试试吗?
答案 4 :(得分:2)
此问题的扩展(IE9中仍然存在)是本机JSON.stringify函数在存在以下情况时崩溃IE:
我们不确定哪个特定点导致崩溃。
我们在这个实例中的解决方法是在stringify函数上使用replacer函数在特定对象属性上返回null并停止遍历对象图。
答案 5 :(得分:-2)
eval(Ext.decode("{"foo":"bar"}"));
正在将