今天,我在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内的所有元素,删除或不删除。
答案 0 :(得分:3)
后门将使用querySelectorAll()
而不是getElementsByTagName()
,它会返回非实时NodeList。
答案 1 :(得分:-1)
尝试删除标记时,您没有使用“引用”,只是指向集合的第一个或第二个元素。要使用引用,您应该使用ID创建标记,然后按ID指向它。数组的关键是第三部分,这就是它将被更新的原因。
另一方面,JavaScript有时是面向对象的事实,有时候它只是一个脚本。