2014-02-17 6 views
0

Сегодня я обнаружил в Javascript что-то вроде «странного поведения» для меня. Давайте предположим, что следующий минимальный пример:Элегантный способ динамического обновления HTMLCollections

HTML:

<div id="test"> 
    <span>1</span> 
    <span>2</span> 
</div> 

JS:

var div = document.getElementById('test'); 
var spans = div.getElementsByTagName('span'); 
div.removeChild(spans[0]); 
div.removeChild(spans[1]); 

(скрипка: http://jsfiddle.net/SkYJg/)

Теперь, при запуске сценария, я получаю сообщение об ошибке:

TypeError: Argument 1 of Node.removeChild is not an object.

Сблизившись, выяснилось, что spans[1] имеет значение после того, как первый был удален. И действительно, следующий код

var div = document.getElementById('test'); 
var spans = div.getElementsByTagName('span'); 
console.log(spans.length); 
div.removeChild(spans[0]); 
console.log(spans.length); 
div.removeChild(spans[1]); 

дает 2 при первой операции журнала, но 1 во второй раз.

Теперь ясно, что здесь происходит: после первого? был удален из DOM, это не часть для того, чтобы HTMLCollection хранился внутри spans.

У меня всегда было впечатление, что объект HTMLCollection -Object содержит ссылки на все объекты, которые он содержит. Я не изменял коллекцию нигде после ее создания. Поэтому я подумал (но это было неправильно, очевидно), что коллекция будет вести себя как массив: ссылки остаются там до тех пор, пока я не удалю их вручную.

Я просмотрел specification at MDN. И действительно, richt наверху говорит: HTMLCollections in the HTML DOM are live; they are automatically updated when the underlying document is changed.

Единственный способ, которым я мог подумать, чтобы предотвратить это, - это перебрать коллекцию, прежде чем что-либо делать с ней, скопировать все ссылки на массив и использовать массив для получить доступ к ним впоследствии. Но это выглядит так ужасно громоздко для меня ... есть ли лучшее решение? Как какой-то способ сделать статическую коллекцию или скопировать ее без циклирования?

(в минимальном примере я мог бы просто удалить spans[0] дважды, конечно, но в действительности это не так просто).

[Изменить]: После просмотра ответа Тейму я повторяю: это НЕ так просто в моем реальном коде (это слишком сложно, чтобы показать его здесь полностью). Уверяю вас, мне действительно нужен произвольный доступ ко всем элементам, которые были внутри этой коллекции, удалены или нет.

+0

Если это касается удаления узлов, то самым простым способом является [цикл через NodeList в обратном порядке] (http://stackoverflow.com/questions/18105426/javascript-function-not-getting-all-values- первый раз/18105542 # 18105542). – CBroe

+0

Это не - см. Править. Может быть, это было более ясно. –

+0

Или вы можете удалить '1', затем' 0'. Я не уверен на 100%, чего вы пытаетесь достичь? – Xotic750

ответ

2

Задняя панель должна использовать querySelectorAll() вместо getElementsByTagName(), она возвращает неживой NodeList.

+0

Я могу использовать только нулевой индекс, если я действительно хотел удалить первые два. Но я не хочу этого, это всего лишь минимальный пример. Мне действительно нужен случайный доступ ко всем элементам, которые были в списке, удалены или нет. –

+0

Что касается 'querySelectorAll': производительность мудрая, она немного медленнее - но я не против. Что меня больше беспокоит, так это строка из спецификации: 'В некоторых случаях NodeList представляет собой живую коллекцию. Это означает, что изменения в DOM отражаются в коллекции. «Вы знаете какие-либо подробности о КОГДА это так? Спецификация на самом деле не ясна ... –

+0

Я печатал, когда вы отвечали, я думал об этом. – Gustavo

-1

Вы не используете «ссылку» при попытке удалить тег, просто указав первый или второй элемент коллекции. Чтобы использовать ссылку, вы должны создать теги с идентификатором и указать его по идентификатору. Ключом Array является третья часть, поэтому она будет обновлена.

С другой стороны, это факт, что JavaScript иногда ориентирован на возражения, а иногда это просто сценарий.

+0

Javascript полностью объектно ориентирован и полностью функциональен. Но это вообще не имеет значения;) Поведение хорошо определено и документировано. И да, я ** делаю ** использую ссылки («ссылка» как «указатель на объект»), единственной альтернативой могут быть копии этих заметок DOM, и это не имеет смысла вообще (я тогда мог бы изменить что-либо внутри коллектора без его влияния на DOM). Любой язык программирования может использовать только копии или ссылки, чтобы предоставить вам доступ к объектам ... –

+0

Поддержка JavaScript объектно-ориентированная, не полностью, а не AS3. Я сказал, что ключ Array не является ссылкой. – Gustavo

+0

Содержание HTMLCollection - это ссылки на объекты HTMLElement, хотя - и это то, о чем я тоже говорил. И внутри Javascript ничего нет (помимо примитивных типов), который не представлен OPbject, поэтому, если он не считается OO, то и Java или C# не имеют таких объектов, как примитивные типы). –

Смежные вопросы