Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>Explanation</h2> <p><code>document.getElementsByClassName</code> returns an <code>HTMLCollection</code>, not just an array of elements. That means that the collection is live, so in this specific situation, it retains the requirement that it will <strong>always</strong> hold <strong>all</strong> elements with the class "current".</p> <p>Coincidentally, you are removing the very <code>class</code> that the collection depends on, therefore updating the collection. It would be totally different if you were setting the <code>value</code> property (for example) in the loop - the collection wouldn't be affected, because the <code>class</code> "current" wasn't removed. It would also be totally different if you were <strong>adding</strong> a class, such as <code>el.className += " none";</code>, but that isn't the case.</p> <p>A great description from the MDN docs:</p> <blockquote> <p>HTMLCollections in the HTML DOM are live; they are automatically updated when the underlying document is changed.</p> </blockquote> <h2>Approach 1</h2> <p>An easy way to overcome all this pandemonium is by looping backwards.</p> <pre><code>var els = document.getElementsByClassName('current'), i = els.length; while (i--) { els[i].className = 'none'; } </code></pre> <p><strong>DEMO:</strong> <a href="http://jsfiddle.net/fAJgT/" rel="noreferrer">http://jsfiddle.net/fAJgT/</a></p> <p>(the code in the demo has a <code>setTimeout</code>, simply so you can see the original border color at first, then after 1.5 seconds, see it change)</p> <p>This works because it modifies the last item in the collection - when it is modified (and automatically removed), move onto the item before it. So it doesn't suffer any consequences of the automatic removal.</p> <p>An alternate setup, doing the same thing, is:</p> <pre><code>for (i = els.length; i &gt;= 0; i--) { </code></pre> <h2>Approach 2</h2> <p>Another answer made me realize you could just continually operate on the first item found. When you remove the specific class, the element is removed from the collection, so you're guaranteed that the first item is always a fresh item in the collection. Therefore, checking the <code>length</code> property should be a safe condition to check. Here's an example:</p> <pre><code>var els = document.getElementsByClassName('current'); while (els.length) { els[0].className = 'none'; } </code></pre> <p><strong>DEMO:</strong> <a href="http://jsfiddle.net/EJLXe/" rel="noreferrer">http://jsfiddle.net/EJLXe/</a></p> <p>This is basically saying "while there's still items in the collection, modify the first one (which will be removed after modified)". I really wouldn't recommend ever using that method though, because it only works <strong>specifically because you end up modifying the collection</strong>. This would infinitely loop if <strong>you were not removing the specific class</strong>, or <strong>with a normal array or a non-live collection (without <code>splice</code>ing)</strong>.</p> <h2>Approach 3</h2> <p>Another option is to <code>slice</code> (shallow copy) the collection into an array and loop through that normally. But I don't see any reason/improvement to do that. Here's an example anyways:</p> <pre><code>var els = document.getElementsByClassName('current'), sliced = Array.prototype.slice.call(els), i; for (i = 0; i &lt; sliced.length; i++) { sliced[i].className = 'none'; } </code></pre> <p><strong>DEMO:</strong> <a href="http://jsfiddle.net/LHe95/2/" rel="noreferrer">http://jsfiddle.net/LHe95/2/</a></p> <h2>Approach 4</h2> <p><strong>Finally</strong>, you could use <code>document.querySelector</code> - it returns a non-live <code>NodeList</code> (therefore you can loop like normal), and even <strong>has better support</strong> in browsers than <code>document.getElementsByClassName</code> does. Here's an example:</p> <pre><code>var els = document.querySelectorAll('.current'), i; for (i = 0; i &lt; els.length; i++) { els[i].className = 'none'; } </code></pre> <p><strong>DEMO:</strong> <a href="http://jsfiddle.net/xq8Xr/" rel="noreferrer">http://jsfiddle.net/xq8Xr/</a></p> <hr> <p><strong>References:</strong></p> <ul> <li><code>document.getElementsByClassName</code>: <a href="https://developer.mozilla.org/en-US/docs/DOM/document.getElementsByClassName" rel="noreferrer">https://developer.mozilla.org/en-US/docs/DOM/document.getElementsByClassName</a></li> <li><code>HTMLCollection</code>: <a href="https://developer.mozilla.org/en-US/docs/DOM/HTMLCollection" rel="noreferrer">https://developer.mozilla.org/en-US/docs/DOM/HTMLCollection</a></li> <li><code>slice</code>: <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice" rel="noreferrer">https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice</a></li> <li><code>querySelectorAll</code>: <a href="https://developer.mozilla.org/en-US/docs/DOM/Document.querySelectorAll" rel="noreferrer">https://developer.mozilla.org/en-US/docs/DOM/Document.querySelectorAll</a></li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload