【发布时间】:2015-01-26 17:54:41
【问题描述】:
简要总结给从 Google 登陆这里的任何人:iOS8 中存在一个错误(仅限 64 位设备),它会间歇性地导致幻像“长度”属性出现在只有数值属性。这会导致 $.each() 和 _.each() 等函数错误地尝试将对象迭代为数组。
我已经向 jQuery (https://github.com/jquery/jquery/issues/2145) 提交了问题报告(实际上是一个解决方法请求),并且在 Underscore 跟踪器 (https://github.com/jashkenas/underscore/issues/2081) 上也存在类似问题。
更新:这是一个已确认的 webkit 错误。 2015 年 3 月 27 日提交了一个修复程序,但没有迹象表明哪个版本的 iOS 将有修复程序。见https://bugs.webkit.org/show_bug.cgi?id=142792。目前已知 iOS 8.0 - 8.3 会受到影响。
更新 2: 可以在 jQuery 2.1.4+ 和 1.11.3+ 以及 Underscore 1.8.3+ 中找到 iOS 错误的解决方法。如果您使用这些版本中的任何一个,则库本身将正常运行。但是,您仍需确保自己的代码不受影响。
这个问题也可以叫做:“没有长度的对象怎么会有长度?”
我在使用移动 Safari 时遇到了一些问题(在运行 iOS 8 的 iPhone 和 iPad 上都可以看到)。我的代码在使用 jQuery ($.each()) 和 Underscore (_.each()) 的“每个”实现时出现了很多间歇性故障。
经过一番调查,我发现在所有失败的情况下,each 函数都将我的对象视为一个数组。然后它会尝试像数组一样迭代它(obj[0]、obj[1] 等)并且会失败。
jQuery 和 Underscore 都使用 length 属性来确定参数是对象还是类数组/数组的集合。例如,Underscore 使用这个测试:
if (length === +length) { ... this is an array
我的对象没有长度参数,但它们触发了上述if 语句。我再次确认没有length by:
- 在调用
each()之前将obj.length的值发送到服务器进行日志记录(确认lengthwas undefined) - 在调用
each()之前先调用delete obj.length(这并没有改变任何东西。)
我终于能够在调试器中捕获此行为,并将 iPhone 连接到 Mac 上的 Safari。
下图显示$.isArrayLike认为length是7。
但是,控制台跟踪显示 length 是 undefined,正如预期的那样:
在这一点上,我认为这是 iOS Safari 中的一个错误,尤其是因为它是间歇性的。我很想听听其他看到此问题并可能找到解决方法的人。
更新
我被要求创建一个小提琴,但不幸的是我做不到。似乎存在时间问题(设备之间甚至可能不同),我无法在小提琴中重现它。这是我能够重现问题的最少代码集,它需要一个外部 .js 文件。这段代码在我运行 8.1.2 的 iPhone 6 上 100% 发生。如果我更改任何内容(例如,使 JS 内联、删除任何不相关的 JS 代码等),问题就会消失。
代码如下:
index.html
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="script.js"></script>
</head>
<body>
Should say 3:
<div id="res"></div>
<script>
function trigger_failure() {
var obj = { 1: '1', 2: '2', 3: '3' };
print_last(obj);
}
$(window).load(trigger_failure);
</script>
</body>
</html>
script.js
function init_menu()
{
var elemMenu = $('#menu');
elemMenu
.on('mouseenter', function() {})
.on('mouseleave', function() {});
elemMenu.find('.menu-btn').on('touchstart', function(ev) {});
$(document).on('touchstart', function(ev) { });
return;
}
function main_init()
{
$(document).ready(function() {
init_menu();
});
}
function print_last(obj)
{
var a = $($.parseHTML('<div></div>'));
var b = $($.parseHTML('<div></div>'));
b.append($.parseHTML('foo'));
$.each(obj, function(key, btnText) {
document.getElementById('res').innerHTML = ("adding " + btnText);
});
}
main_init();
【问题讨论】:
-
你能展示你是如何构建你的对象的吗?你能在小提琴中重现这个问题吗?
-
您的观察的许多可能原因浮现在脑海中。我们确实需要更多代码来为您提供诊断。
-
那个特定的对象是用内联代码简单地构建的 `{ 1: 'Just me', 2: '2', 3: '3', 4: '4', 5: '5' , 6: 'More than 5' } 并作为参数传递给另一个名为 $.each() 的函数。
-
您能在fiddle 中重现问题吗?
-
@dystroy 我看看能不能搞定它。
标签: javascript jquery ios underscore.js mobile-safari