Strange result using "for(in... " iteration

Joined
Jan 6, 2022
Messages
21
Reaction score
0
In playing around with iteration methods I stumbled across this confusing outcome.

Method 1 code with a standard loop has the expected array property length of 2 and alerts for each pet but the second method using a "for(in …” iteration gives an extra 3 alerts . So it seems “arr” has extra (undefined) items. Hope someone can tell me why.

And, yes, I’m using JS to write the HTML elements instead of hard coding them.

Code:
<script>
    function go(){
arr=document.getElementsByClassName("pet");
        
        alert("method 1")
           for(i=0;i<arr.length;i++) // 2 alerts
        {alert(arr[i].innerHTML)} // show contents
                
        alert('method 2');
        for ((n) in arr)          // 5 alerts
        {alert(arr[n].innerHTML)} // show contents

}
    document.write
    ("<div class='pet' hidden>dog</div>\
    <div class='pet' hidden>cat</div>\
<button onclick=go()>click to run</button>")
</script>
 
Joined
Sep 4, 2022
Messages
136
Reaction score
16
hello !



by the 'for (n) in arr' , you are reading array properties and its own content.
it returns your array custom settings, and all vars in. it makes more datas to fetch.

to avoid weird feedbacks stay on 'for loop'
 
Joined
Jul 4, 2023
Messages
503
Reaction score
63
The arr returned by document.getElementsByClassName('pet') is not a regular JavaScript array, but an HTMLCollection. While it behaves like an array in some respects, it is technically an object with enumerable properties. In this case:
  • The HTMLCollection might have additional properties that are not part of the actual "pet" elements, which are being iterated over with the for-in loop.
  • When you use for-in, it loops over every property in the object, including non-numeric keys (like: length, item, namedItem, etc.), which results in extra alerts for undefined or irrelevant items.
Use the test without innerHTML and let's see what happens [ on-line ].
HTML:
<div class='pet' hidden>dog</div>
<div class='pet' hidden>cat</div>
<button onclick=test()>click to run test</button>
<pre></pre>

<script>
  const console_ = document.querySelector('pre');
 
  function test() {
    const html_collection = document.getElementsByClassName('pet');
    console_.textContent += [...html_collection].map(e => e.outerHTML).join('\n');
    showMethodOne('getElementsByClassName', html_collection);
    showMethodTwo('getElementsByClassName', html_collection);
 
    console_.textContent += '\n\n';
 
    const node_list = document.querySelectorAll('.pet');
    console_.textContent += [...node_list].map(e => e.outerHTML).join('\n');
    showMethodOne('querySelectorAll', node_list);
    showMethodTwo('querySelectorAll', node_list);
  }
 
  function showMethodOne(name, object) {
    console_.textContent += '\n\n' + `Method 1 - ${name}` + '\n';
    for (let i=0; i<object.length; i++)
      console_.textContent += `${object[i]} ${object[i].nodeName} `
        + `${object[i].className} `
        + `${object[i].textContent} `
        + `[${[...object[i].attributes].map(a => a.name).join(', ')}]`
        + '\n';
  }
  function showMethodTwo(name, object) {
    console_.textContent += '\n\n' + `Method 2 - ${name}` + '\n';
    for (const n in object)
      if (! Number(object[n]))
        console_.textContent += object[n] + '\n';
      else
        console_.textContent += 'properties length ' + object.length + ' [read only]' + '\n';
  }
</script>

<style>
  pre {
    width: 90dvw;
    background-color: black;
    color: limegreen;
    padding: .5rem;
  }
  pre:empty {
    opacity: 0;
  }
</style>
1732607035955.png


BTW,
HTML:
<div class='pet' hidden>dog</div>
<div class='pet' hidden>cat</div>
<button onclick=test()>click to run test</button>
<pre></pre>

<script>
  const console_ = document.querySelector('pre');

  function test() {   
    const html_collection = document.getElementsByClassName('pet');
    showTitle('getElementsByClassName');
    console_.textContent += [...html_collection].map(e => e.outerHTML + ' ' + e).join('\n') + '\n';

    showTitle('Method - for...of');
    for (const n of html_collection)
      console_.textContent += `${n} ${n.nodeName} ${n.innerText}` + '\n';
    showTitle('Method - forEach');
    [...html_collection].forEach((n) => {
      console_.textContent += `${n} ${n.nodeName} ${n.innerText}` + '\n';
    });

    console_.textContent += '\n';

    const node_list = document.querySelectorAll('.pet');
    showTitle('querySelectorAll');
    console_.textContent += [...node_list].map(e => e.outerHTML + ' ' + e).join('\n')+ '\n';

    showTitle('Method - for...loop');
    for (let i=0; i<node_list.length; i++)
      console_.textContent += `${node_list[i]} ${node_list[i].nodeName} ` + '\n';
    showTitle('Method - for...of');
    for (const n of node_list)
      console_.textContent += `${n} ${n.nodeName} ${n.innerText}` + '\n';
    showTitle('Method - forEach');
    node_list.forEach((n) => {
      console_.textContent += `${n} ${n.nodeName} ${n.innerText}` + '\n';
    });
  }

  function showTitle(name) {
    console_.textContent += '\n' + name + '\n';
  }
</script>

<style>
  pre {
    width: 90dvw;
    background-color: black;
    color: limegreen;
    padding: .5rem;
  }
  pre:empty {
    opacity: 0;
  }
</style>
1732611162007.png
 
Last edited:

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,039
Messages
2,570,376
Members
47,031
Latest member
AndreBucki

Latest Threads

Top