围绕HTMLCollections动态更新的优雅方式

时间:2014-02-17 17:16:17

标签: javascript dom htmlcollection

今天,我在Javascript中发现了一些看起来像“奇怪行为”的东西。让我们假设以下最小的例子:

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:Node.removeChild的参数1不是对象。

仔细观察,结果发现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。事实上,顶部的富人说:HTMLCollections in the HTML DOM are live; they are automatically updated when the underlying document is changed.

我能想到的唯一方法就是在使用它之前循环遍历collectino,复制对数组的所有引用,然后使用数组访问它们。但这对我来说看起来非常笨重......是否有更好的解决方案?像某种方式使集合静态或复制它而不循环?

(在最小的例子中,我当然可以删除spans[0]两次,但实际上并不是那么简单。)

[编辑]:在看到@Teemu的回答之后,我再说一遍:在我的真实代码中并不是那么简单(一个太复杂而无法完全显示在这里)。我向你保证,我真的需要随机访问该Collection内的所有元素,删除或不删除。

2 个答案:

答案 0 :(得分:3)

后门将使用querySelectorAll()而不是getElementsByTagName(),它会返回非实时NodeList

答案 1 :(得分:-1)

尝试删除标记时,您没有使用“引用”,只是指向集合的第一个或第二个元素。要使用引用,您应该使用ID创建标记,然后按ID指向它。数组的关键是第三部分,这就是它将被更新的原因。

另一方面,JavaScript有时是面向对象的事实,有时候它只是一个脚本。