getElementsByClassName vs querySelectorAll

That’s because HTMLCollection returned by getElementsByClassName is live.

That means that if you add "class" to some element’s classList, it will magically appear in temp.

The oposite is also true: if you remove the "class" class of an element inside temp, it will no longer be there.

Therefore, changing the classes reindexes the collection and changes its length. So the problem is that you iterate it catching its length beforehand, and without taking into account the changes of the indices.

To avoid this problem, you can:

  • Use a non live collection. For example,

    var temp = document.querySelectorAll(".class");
    
  • Convert the live HTMLCollection to an array. For example, with one of these

    temp = [].slice.call(temp);
    temp = Array.from(temp); // EcmaScript 6
    
  • Iterate backwards. For example, see @Quentin’s answer.

  • Take into account the changes of the indices. For example,

    for (var i=0; i<temp.length; ++i) { 
     temp[i].className = "new_class";
     --i; // Subtract 1 each time you remove an element from the collection
    }
    
    while(temp.length) { 
     temp[0].className = "new_class";
    }
    

Leave a Comment