Array method not available? "Sort is not a Function" error when applying it to Nodelist

Asked

Viewed 70 times

2

I have the following code:

var letterDivs = gameBox.getElementsByClassName("wordBox")[0].childNodes;

console.log(letterDivs); //=> NodeList[...]

// Dá erro: `sort is not a function`:
letterDivs.sort((a, b) => {
  a.style.order > b.style.order ? 1 : -1;
});

Here’s what the console.log(letterDivs) get back to me:

O que console.log(letterDivs) retorna

Since it’s an array I’m trying to use the method sort but gives error. Why? How to solve this problem? The goal is to sort the letters in order of the style property order.

It also does not work with other "common" arrays methods, such as map and filter. Why?

2 answers

4

It is not an array, it is a DOM Nodelist. You can use the following:

Array.prototype.sort.call(letterDivs, (a, b) => ...)

4


The problem is you’re not working with a Array, but rather with a NodeList. Methods such as the getElementsByClassName or the querySelectorAll do not return an array, but rather a collection of DOM elements. This collection is called NodeList and is a different object from Array (and therefore does not implement all methods of "conventional arrays", such as the sort, filter, map, etc.).

In this sense, as the method sort is implemented in the prototype of Array, one option is to convert your NodeList to an array before using it. Below I show some options for this.


Like NodeList implements the language iteration protocol, you can use the scattering operator to convert it into a Array:

[...letterDivs].sort((a, b) => /* ... */);

In the above example, [...letterDivs] is an expression that evaluates to an array. So we can use sort afterward.

Another option is to use Array.from, which also returns an array:

Array.from(letterDivs).sort((a, b) => /* ... */);

One observation is that the two above formats return an array. So, the expression does not return one NodeList, but rather a Array.


You might consider using Function.prototype.call or Function.prototype.apply, but as the method Array.prototype.sort does not copy the this (which is usually an original array), modifications are made to the given value itself as argument this.

So if you use a NodeList as this of sort, may end up getting an error like "Failed to set an Indexed Property". Can end up modifying the GIFT unintentionally as well, since NodeList is a "live list".

  • But when I do a console.log of letterDivs after Sort returns me a nodelist. Why?

  • Hmm, it’s true. I edited the answer. :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.