Array.prototype.slice: 'this' не является ошибкой объекта JavaScript в IE8

Насколько я понимаю, IE8 имеет доступ к методу Array.prototype.slice. Тем не менее, когда я пытаюсь вызвать его, чтобы превратить NodeList в массив, он выдает ошибку Array.prototype.slice: 'this' is not a JavaScript object. Вы можете проверить это здесь или посмотреть мой код здесь:

HTML

<div id="test">Test</div>

JavaScript

var divs = document.getElementsByTagName('div');
divs = Array.prototype.slice.call(divs);
console.log(divs);

Что тут происходит?


person Aust    schedule 09.11.2012    source источник


Ответы (3)


Обновление: NodeList некоторым образом можно рассматривать как массив - на самом деле вам не нужно делать с ним ничего особенного, прежде чем вы сможете его перебрать, например:

var aDivs = [];
for (var = i = 0; i < divs.length; i++) {
    aDivs.push(divs[i]);
}

Это создаст массив со всеми узлами, которые совпали при запуске document.getElementsByTagName()

См. этот вопрос для полное объяснение того, почему slice работает с NodeList в некоторых браузерах, но не в других, но это сводится к этому предложению из спецификации:

Возможность успешного применения функции среза к объекту хоста зависит от реализации.

person Kelvin    schedule 10.11.2012
comment
Это не работает, потому что divs не является экземпляром Array. Это экземпляр NodeList. При попытке сделать это возвращает ошибку Object doesn't support property or method 'slice'. Использование .call() делает так, что this относится к правильному объекту. - person Aust; 10.11.2012
comment
Вы абсолютно правы - извинения; Я обновил свой ответ. Я подозреваю, что причина, по которой вы получаете эту ошибку, проста в том, что поскольку NodeList не является обычным объектом Javascript, slice не может с ним работать. - person Kelvin; 10.11.2012

Сообщение об ошибке точное - ваш список узлов не является объектом JavaScript, это "объект хоста", которые вы не можете передавать, как обычные объекты JavaScript. Запустите этот код в консоли JavaScript IE8:

document.querySelectorAll("div") instanceof Object

Возвращает false.

person gilly3    schedule 10.11.2012

Я предполагаю, что вы хотите сохранить тот же контент, даже если набор NodeList изменится.

Если это так, плохие новости: IE8 сломан. И он не может справиться с использованием фрагмента в NodeList.

Таким образом, вам нужно будет использовать запасной вариант и самому сделать «срез», когда срез завершится неудачно (с помощью try / catch).

Обратите внимание: если вы не ожидаете, что DOM изменится, и если объекта, подобного массиву, достаточно, вы можете просто использовать NodeList, как любой другой массив (за исключением того, что это не так, и что, возможно, он будет изменен, если DOM изменения).

[edit] На самом деле это не сломанный дизайн, это разрешено стандартом (как указано по ссылке в комментарии Кельвина Маккея)

person Maël Nison    schedule 10.11.2012
comment
На этот раз IE сходит с рук, выполнив полупечетую работу по техническим вопросам, лол. - person Kelvin; 10.11.2012