17

According its w3schools page (everyone's favorite resource, I know), the .children property returns

A live HTMLCollection object, representing a collection of element nodes

This object can be looped over as if it were an array like so:

var elements = document.getElementById('test').children;

for (var i=0; i < elements.length; i++) {
  console.log(elements[i]);
}
<div id="test">
  <p>paragraph 1</p>
  
  <p>paragraph 2</p>
  
  <p>paragraph 3</p>
</div>

However attempting to use the .map function throws an error:

var elements = document.getElementById('test').children;

var x = elements.map((element, index) => {
  console.log(element);
});
<div id="test">
  <p>paragraph 1</p>

  <p>paragraph 2</p>

  <p>paragraph 3</p>
</div>

Is there a better way to get an array of child DOM elements, or do I have to loop through the object and manually create an array in order to use array methods like .map()? Note, I do not want to use jQuery. Thanks in advance.

dougmacklin
  • 2,560
  • 10
  • 42
  • 69
  • 2
    `Array.from(elements)` P.S. Please oh _please_ don't use [w3schools](http://www.w3fools.com/) as your reference! – Patrick Roberts Jun 14 '16 at 20:38
  • What are you trying to achieve with `.map`? – putvande Jun 14 '16 at 20:40
  • Thanks @PatrickRoberts and believe me I have the same issues with w3schools as everyone else, however every other search result for .children discusses the jQuery method. – dougmacklin Jun 14 '16 at 20:50
  • @putvande I need to convert the contents of a
    to a JSON array
    – dougmacklin Jun 14 '16 at 20:52
  • Cool, I was basing my searches around trying to find more information about .children, sorry for not searching htmlcollection. That question is 8 years old, however, and doesn't contain the ES6 solution that @SterlingArcher proposed, which I am going to use. Thanks for your help Patrick. – dougmacklin Jun 14 '16 at 21:01

1 Answers1

25

.map expects an array. You need to convert this array-like object (HTMLCollection) into a real array. There are several methods, but my 2 favorite are ES6 spread, and array from.

Array.from(document.getElementById('test').children).map

Or spreading

[...document.getElementById('test').children].map

If you don't want to use ES6, you can slice and force an array conversion, or [].slice.call(document.getElementById('test').children) I believe would also do a conversion.

As Patrick said in the comments: [].slice.call, not [].call. Might also want to mention the more wordy Array.prototype.slice.call since it doesn't initialize an unused empty array

The key here is that an HTMLCollection is an object, where map is an Array function.

Sterling Archer
  • 22,070
  • 18
  • 81
  • 118
  • Whoops, good catch! – Sterling Archer Jun 14 '16 at 20:43
  • Thanks for your help @SterlingArcher! I understand that it's not an array and that it needs to be converted. Do you know if there a difference in efficiency between `Array.from()` and the spread method? I am fine using ES6. – dougmacklin Jun 14 '16 at 20:48
  • 4
    You could also use call on the map directly `Array.prototype.map.call( element.children, mappingFunction)` – ashwell Jun 14 '16 at 20:57