问题
Today, I discovered something in Javascript that looked like "strange behavior" to me. Let's assume the following minimal example:
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]);
(Fiddle: http://jsfiddle.net/SkYJg/)
Now, when running the script, I get an error:
TypeError: Argument 1 of Node.removeChild is not an object.
Looking closer, it turned out that spans[1]
is null after the first one was removed. And indeed, the following code
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]);
yields 2
at the first log operation, but 1
the second time.
Now, it's pretty clear what happens here: after the first ?span? was removed from DOM, it's not part fo that HTMLCollection
stored inside spans
anymore either.
I always was under the impression, that the HTMLCollection
-Object holds references to all objects that it contains. I didn't modify the collection anywhere after creating it. So I thought (but it was wrong, obviously) that the collection would behave like an array: references stay there until I delete/modify them manually.
I looked into the specification at MDN. And, indeed, richt at the top it says: HTMLCollections in the HTML DOM are live; they are automatically updated when the underlying document is changed.
The only way I could think of to prevent this is to loop over the collectino before doing anything with it, copying all references to an array, and use the array to access them afterwards. But that just looks so horribly bulky to me... is there a nicer solution? Like some way to make the collection static or to copy it without looping?
(in the minimal example I could just remove spans[0]
twice, of course, but it isn't that simple in reality).
[Edit]: After seeing @Teemu's answer, I repeat: it's NOT that simple in my real code (that one is just too complex to show it here completely). I assure you, I really need random access to all elements that were inside that Collection, deleted or not.
回答1:
A back-gate would be to use querySelectorAll() instead of getElementsByTagName()
, it returns a non-live NodeList.
回答2:
You're not using a "reference" when trying to remove the tag, just pointing the first or the second element of a collection. To use reference, you should create tags with ID and than point it by ID. The key of an Array is a third part, that's why it will be updated.
On the other hand, is a fact that JavaScript is objected-oriented sometimes, and other times it is just a script.
来源:https://stackoverflow.com/questions/21835282/elegant-way-around-htmlcollections-updating-dynamically