QuerySelectorAll and getElementsByTagName, for/of and forEach | JavaScript, Node.js, React.js and Angular.js Forum
Y
Yogesh Chawla Posted on 25/12/2022
Was practising dom manipulation..
was trying to solve the exercise 02 here 

html
<body>
<p>
  We have just <b>started</b> this <b>section</b> for the users (<b>beginner</b> to <b>intermediate</b>) who want to work with various <b>JavaScript</b> problems and write scripts online to test their <b>JavaScript</b> skill.
</p>
</body>

.highlight {
  background-color: #FFFF00
}

.nohighlight {
  background-color: white
}

my JS solution
let allboldElems = document.querySelectorAll('b');
allboldElems.forEach((elem) => {
  elem.addEventListener("mouseover", function() {
    elem.setAttribute('class', 'highlight');
  });
  elem.addEventListener("mouseout", function() {
    elem.setAttribute('class', 'nohighlight');
  });
});

this worked
2 questions. may be you could explain why

1. when I used getElementsByTagName instead of querySelectorAll it didn't work. 
2. even with queryselectorall, if I used a for of instead of forEach it didn't work, i.e., it would highlight/dehighlight only the last "b" element if I used for of

// for(var e of allboldElems) {
//   e.onmouseover = function() {
//     e.setAttribute('class', 'highlight');
//   };
//   e.onmouseout = function() {
//     e.setAttribute('class', 'nohighlight');
//   };
// }

Y
Yogesh Chawla Replied on 25/12/2022

Difference between getElementsByTagName method and querySelectorAll method:


Selections:
getElementsByTagName only selects elements based on their tag name. 
querySelectorAll can use any selector which gives it much more flexibility and power.
In your case, you have just passed a tag name so it works for both gEBTN and qSA.

Second
Return value
gEBTN returns a live node list.
qSA returns a static node list.

Live node lists is - you query once, store the value, and have it updated as the DOM changes.

Whereas NodeList object returned by the querySelectorAll() method is static, not live. Subsequent changes to the structure of the underlying document must not be reflected in the NodeList object. This means that the object will instead contain a list of matching Element nodes that were in the document at the time the list was created.

That is the reason, in your case, with querySelectorAll() it is working and with  
getElementsByTagName, it is not
Because with getElementsByTagName, we are on the last bold tag and that's the reason it is working with for each for last bold tag 




Now with the two constructs, forEach() and for/of, you get access to the array element itself but with forEach(), you can access the array index i also and with for/of you cannot.

<!DOCTYPE html>
<html>
    <body>
        <p id ="demo"></p>
        <script>
        const foodArray = [
    			{ name: 'Burrito' },
    			{ name: 'Pizza' },
    			{ name: 'Burger' },
    			{ name: 'Pasta' }
    		];
    foodArray.forEach((food, index) => {
      console.log(`value: ${index} | Food Name:`, food);
    });
    //whereas with for/of, this is who we can write code
        var text = [
            "JS.com - ",
            " A Computer Science Portal for JS ", 
            "43"
            ];
        var userId = "";
        var i;
        for (i of text) {
        userId+=i;
        }
        document.getElementById("demo").innerHTML = userId;
        </script>
    </body>
</html>

Output on UI:
JS.com - A Computer Science Portal for JS 43

On Console:
"value: 0 | Food Name:", {
  name: "Burrito"
}
"value: 1 | Food Name:", {
  name: "Pizza"
}
"value: 2 | Food Name:", {
  name: "Burger"
}
"value: 3 | Food Name:", {
  name: "Pasta"
}

That's the reason, you are able to change colors of each bold tag using 
forEach

Now to make it work with both gEBTN and for/of, use this:

let allboldElems = //document.querySelectorAll('b');
document.getElementsByTagName('b');
allboldElems = [...allboldElems]

allboldElems.forEach((elem) => {
  elem.addEventListener("mouseover", function() {
    elem.setAttribute('class', 'highlight');
  });
  elem.addEventListener("mouseout", function() {
    elem.setAttribute('class', 'nohighlight');
  });
});


In ES6 you can use the spread operator to convert an HtmlCollection to an Array. 

input = [...input]
input.forEach(ShowResults)

Spread operator allows an iterable to expand in places where more than one arguments are expected. It allows us the privilege to obtain a list of parameters from an array. Syntax of Spread operator is same as Rest parameter but it works completely opposite of it.

Syntax:

var variablename1 = [...value]; 

In the above syntax, … is spread operator which will target all values in particular variable. When … occurs in function call or alike,its called a spread operator. 


To get the index in a for-of loop, we need to call the array with a entries() method and use destructuring syntax.

use this:

let allboldElems = //document.querySelectorAll('b');
document.getElementsByTagName('b');
allboldElems = [...allboldElems]

for(const [index,value] of allboldElems.entries()){

   value.onmouseover = function() {
     value.setAttribute('class', 'highlight');
   };
   value.onmouseout = function() {
     value.setAttribute('class', 'nohighlight');
   };
 }