0

I have this simple javascript snippet

function foo() {
  bar();
}

function bar() {
  var tags = document.getElementsByTagName('example');
  
  for (var i = 0; i < tags.length; i++) {
    console.log(tags.length);
    tags[i].innerHTML = '<example2>Inserted</example2>';
  }
}

foo();
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.2/lodash.min.js"></script>
<example></example>

The thing I don't get is that when I change the inserted innerHTML to be Inserted it doesn't exit the loop as it keeps "updating" the variable tag (I added the 2 in the snippet to avoid it if you run it);

As a side note, if I use the lodash forEach it does what I expected to do with the for loop, just runs the loop code once.

function foo() {
  bar();
}

function bar() {
  var tags = document.getElementsByTagName('example');

  _.forEach(tags, function(value) {
    console.log(tags.length);
    value.innerHTML = '<example>Inserted</example>';
  });
}

foo();
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.2/lodash.min.js"></script>
<example></example>

I can't understand why the loop keeps udpdating the variable with the nested tags.

Thanks

1 Answer 1

3

document.getElementsByTagName and its sibling DOM methods return a live HTMLCollection of elements, meaning that if the new elements that match your query are added, the variable containing the reference to the HTMLCollection will be updated. You should either:

a) Use Array.from to "detach" the collection:

var tags = Array.from(document.getElementsByTagName('element'));

Or if you don't have Array.from available, you could use Array.prototype.slice:

var tags = Array.prototype.slice.call(document.getElementsByTagName('a'), 0)

b) Not add elements that match the query you are iterating over (which is creating an infinite loop)


This is also why it's suggested that if you are iterating over a collection of elements in a for loop, you capture the length of the list prior to iteration and use it as the loop boundary:

var tags = document.getElementsByTagName('example');
var length = tags.length;

for (var i = 0; i < length; i++) {
   // won't be infinite
   document.createElement('example');
   ...
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.