Array-like Objects

Published: Monday, November 2, 2020

Greetings, friends! Today, I'd like to talk about a topic you may not hear very often: array-like objects. When working with the Array.from method, you'll see in the documentation that it accepts an arrayLike parameter or an iterable. What are array-like objects, though? Let's find out!

An array-like object is simply an object that contains indices and a length property. Obviously, arrays are considered array-like, since they fulfill both criteria.

javascript
Copied! ⭐️
const arr = ['a', 'b', 'c', 'd', 'e'];

console.log(Object.keys(arr)); // ["0", "1", "2", "3", "4"]
console.log(arr.length); // 5

An array is considered a type of object in JavaScript:

javascript
Copied! ⭐️
const arr = ['a', 'b', 'c', 'd', 'e'];

console.log(typeof arr); // object

This is why we're able to use Object.keys(arr) to display the array's keys. Each element in an array represents a value in an object's key-value pair.

Let's try to create our own array-like object:

javascript
Copied! ⭐️
const iceCreamFlavors = {
  0: 'vanilla',
  1: 'chocolate',
  2: 'strawberry',
  3: 'blueberry',
  4: 'mango'
}

If we try calling Array.from on this object, let's see what happens:

javascript
Copied! ⭐️
console.log(Array.from(iceCreamFlavors));
// OUTPUT: []

We get an empty array. That's because we're missing one key ingredient! No pun intended 😂. We need to add a length property as well:

javascript
Copied! ⭐️
const iceCreamFlavors = {
  0: 'vanilla',
  1: 'chocolate',
  2: 'strawberry',
  3: 'blueberry',
  4: 'mango'
}

iceCreamFlavors.length = Object.keys(iceCreamFlavors).length;

console.log(Array.from(iceCreamFlavors));
// OUTPUT: ["vanilla", "chocolate", "strawberry", "blueberry", "mango"]

Ta-da! 🎉 We have created a delicious array-like object! 😋

Where is this knowledge more applicable? It turns out that the document.querySelectorAll method actually returns an array-like object for us! This method returns a NodeList object. It may look like an array, but it doesn't act like one.

If it doesn't quack like a duck, but it looks like a duck, is it really a duck? 🤔 Please excuse my pondering. I'm referencing duck typing in case you're curious 😃.

Let's look at an example. Suppose we have three div elements:

html
Copied! ⭐️
<div id="one">Div #1</div>
<div id="two">Div #2</div>
<div id="three">Div #3</div>

If we run a query selector on all of these divs, we get back an object that looks like an array. However, we can't perform any usual array methods on it such as Array.map:

javascript
Copied! ⭐️
const divs = document.querySelectorAll('div');

console.log(divs); // NodeList(3) [div#one, div#two, div#three]

console.log(divs instanceof Array) // false

const map = divs.map(el => console.log(el)); // Uncaught TypeError: divs.map is not a function

Just for curiosity's sake, let's see what happens if we try running the forEach method:

javascript
Copied! ⭐️
const divs = document.querySelectorAll('div');

divs.forEach(el => console.log(el));
/* OUTPUT:
<div id="one">Div #1</div>
<div id="two">Div #2</div>
<div id="three">Div #3</div>
*/

You may be thinking there's something special about Array.forEach, but in reality, you're actually using the NodeList.forEach method if you try calling forEach on a NodeList returned by the document.querySelectorAll method. Please keep this in mind if you're working with NodeLists!

In order to use array methods on a NodeList, we need to convert it to an array using Array.from. Since it has indices and a length property, it falls under the category of being an array-like object.

javascript
Copied! ⭐️
const divs = document.querySelectorAll('div');

// Indices ✅
console.log(Object.keys(divs)); // [0, 1, 2]

// Length property ✅
console.log(divs.length); // 3

// Convert to array
const divsArr = Array.from(divs);

// Array methods now work! 🎉
divsArr.map(el => console.log(el));
/* OUTPUT
<div id="one">Div #1</div>
<div id="two">Div #2</div>
<div id="three">Div #3</div>
*/

Conclusion

If you're ever dealing with objects in JavaScript that look like arrays but aren't quite, then you might be dealing with array-like objects. Keep this in mind as you're reading through documentation on various methods in the DOM API.