Краткий обзор для всех, кто приземляется здесь от Google: в iOS8 есть ошибка (только на 64-разрядных устройствах), которая периодически вызывает свойство phantom "length", которое появляется на объектах, которые имеют только числовые свойства. Это вызывает такие функции, как $.each() и _.each(), чтобы попытаться выполнить итерацию вашего объекта в виде массива.
Я опубликовал отчет об ошибке (действительно, обходной запрос) с jQuery (https://github.com/jquery/jquery/issues/2145), и есть аналогичная проблема на Подчеркивание трекера (https://github.com/jashkenas/underscore/issues/2081).
Обновление: Это подтвержденная ошибка веб-кита. Исправление было выполнено в 2015-03-27, но нет никаких указаний относительно того, какая версия iOS будет иметь исправление. См. https://bugs.webkit.org/show_bug.cgi?id=142792. В настоящее время известно, что iOS 8.0 - 8.3 затронуты.
Обновление 2: Обходной путь для ошибки iOS можно найти в jQuery 2.1.4+ и 1.11.3+, а также в Underscore 1.8.3+. Если вы используете какую-либо из этих версий, то сама библиотека будет вести себя правильно. Однако вам все равно, чтобы ваш собственный код не был затронут.
Этот вопрос также можно вызвать: "Как объект без длины имеет длину?"
У меня проблема с сумеречной зоной с мобильным Safari (видно на обоих iPhone и iPad, работающих под управлением iOS 8). В моем коде много прерывистых сбоев, использующих "каждую" реализацию как jQuery ($.each()
), так и Underscore (_.each()
).
После некоторого расследования я обнаружил, что во всех случаях сбоя функция each
обрабатывала мой объект как массив. Затем он попытался бы повторить его как массив (obj[0]
, obj[1]
и т.д.) И потерпит неудачу.
Оба jQuery и Underscore используют свойство length
, чтобы определить, является ли аргумент объектом или массивом или массивом. Например, Underscore использует этот тест:
if (length === +length) { ... this is an array
У моих объектов не было параметра длины, но они вызывали вышеуказанные выражения if
. Я дважды подтвердил, что не было length
:
- Отправка значения
obj.length
на сервер для ведения журнала до вызоваeach()
(подтверждение того, чтоlength
was undefined
) - Вызов
delete obj.length
до вызоваeach()
(это ничего не изменило.)
Наконец-то я смог зафиксировать это поведение в отладчике с iPhone, прикрепленным к Safari на Mac.
На следующем рисунке показано, что $.isArrayLike считает, что length
равно 7.
Однако консольная трасса показывает, что length
- undefined
, как и ожидалось:
В этот момент я считаю, что это ошибка в Safari iOS, тем более, что она прерывистая. Мне бы хотелось услышать от других, кто видел эту проблему, и, возможно, нашел способ противостоять ей.
Update
Меня попросили создать скрипку, но, к сожалению, я не могу. Кажется, существует проблема синхронизации (которая может даже отличаться между устройствами), и я не могу воспроизвести ее в скрипке. Это минимальный набор кода, с которым я смог воспроизвести проблему, и требует внешнего .js файла. С этим кодом происходит 100% времени на моем iPhone 6, работающем под управлением 8.1.2. Если я что-то изменил (например, сделав JS inline, удалив любой из несвязанных 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();