I'm watching Shaun Pelling's Modern JavaScript course on Udemy (great way to get started, by the way) — and I just worked through an example that doesn't seem like it should have worked.
The challenge was to iterate through all of the elements within an article
tag and add a class to each one:
<article id="example-article">
<h2>Article Title</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
<div>Written by the Some Person</div>
</article>
Selecting querySelector
returns an HTMLCollection
, which can't be iterated through by using forEach()
. Instead Shaun recommended using the Array.from
method and iterating through that instead.
Cool! Easy enough:
const article = document.querySelector('#example-article');
const articleContents = article.children;
let copiedContents = Array.from(articleContents);
copiedContents.forEach(child => {
child.classList.add('article-element');
});
And that's it. The DOM was updated with the new classes. Here's my question:
I thought Array.from()
made a new array from the information in the HTMLCollection
. I thought for sure that I was going to have to do something like article.innerHTML = [...copiedContents]
or something, but I didn't have to copy the new array back into the article element at all. In fact when I console.log(article.children);
I get:
HTMLCollection(5)
0: <h2 class="article-element">
1: <p class="article-element">
2: <p class="article-element">
3: <p class="article-element">
4: <div class="article-element">
length: 5
How?
Top comments (3)
HTMLCollection
may looks like an Array but it isn't, hence theArray.from()
or[...copiedContents]
, since you'll need to transform it on an actual array for performing some array-like operations.Doing so changes the iterable data structure: it is, indeed, not the original
copiedContents
, but the insides are the same DOM references to elements, you didn't make new ones. This article should help you understand it a bit.Got it. So, copying the
HTMLCollection
into a new array usingArray.from()
also copied all of the references to the original, thus changes to the copy reflected back to the DOM. That seems convenient and dangerous at the same time.Yeah, right!
This is the nature of working with DOM elements, don't know if I'm just used to it. It's very reference-y and with a bunch of side-effects, I believe that's why we use libs like React, since we almost don't have to deal with this.