What are Array‑Like Objects in JavaScript?

Hero image for What are Array‑Like Objects in JavaScript? Image by Ash Edmonds.
Hero image for 'What are Array‑Like Objects in JavaScript?' Image by Ash Edmonds.

In the world of frontend development and JavaScript, we developers often encounter structures that resemble arrays, yet aren't true arrays. These are called "arraylike objects", and understanding these unique constructs is crucial for effective JavaScript programming.


What are Array‑Like Objects?

Arraylike objects are objects that have a length property and indexed elements, similar to arrays. However, they lack the arrayspecific methods like forEach(), map(), and slice() that are available on true JavaScript arrays via the Array.prototype constructor.

Common Examples in JavaScript

  • NodeList: Returned by methods like document.querySelectorAll.
  • arguments: An object accessible within functions representing the arguments passed to that function.

Array‑Like Objects in Other Languages

As you might imagine, the concept of arraylike objects isn't unique to JavaScript. Many programming languages have similar concepts, where structures behave like arrays but aren't arrays in the strictest sense. For example, in Python, range() generates a sequence that is arraylike.


Working with Array‑Like Objects in JavaScript

Example: NodeList

When you use document.querySelectorAll, it returns a NodeList:

const divs = document.querySelectorAll('div');console.log(divs.length);  //=> a number that represents the number of div elements within the document

Here, divs is a NodeList, which is an arraylike object, meaning you can access elements with their index (e.g., divs[0]), and you can read its length via .length(). Relatively recent updates to the DOM standard even allow NodeList to be directly iterated over using forEach(). This wasn't always the case.

However, it is important to note that not all array methods are available on a NodeList. If you need to use other array methods like map() or filter(), you would still need to convert the NodeList to an actual array using Array.from() or the spread operator.

Example: arguments

The arguments object in a function is another example of an arraylike object where you have access to some but not all Array features.

const sum = (...args: number[]): number =>  args.reduce((sum, current) => sum + current, 0);console.log(sum(1, 2, 3));  //=> 6

Here, we have a simple function that calculates the sum of an arbitrary number of arguments passed to it. We're using rest parameters to directly gather any number of arguments, into an array (...args). Having grouped them into an array, it then calculates their sum.


Converting Array‑Like Objects to Arrays

Unsurprisingly, one of the common tasks when dealing with arraylike objects in JavaScript is converting them into 'actual' arrays, thus allowing us access to use all of the array methods on our data (like map, filter, reduce, etc.) which might otherwise be unavailable on this type of structure.

There are two main methods you can use when performing this conversion: using Array.from(), or the spread operator (...).

Using Array.from()

Array.from() creates a new, shallowcopied Array instance from an arraylike or iterable object. It's a straightforward and readable way to perform the conversion.

A Set is an iterable object that can be converted to an array using Array.from(). This is useful when you need array functionalities on a Set, for example:

const aSet = new Set([1, 2, 3, 4, 5]);const anArray = Array.from(aSet);console.log(anArray);  //=> [1, 2, 3, 4, 5]

Using the Spread Operator

The spread syntax (...) allows an iterable object such as an array expression or string to be expanded in places where zero or more arguments or elements are expected. So you can just spread your const for example: const anArray = [...aSet];.

However, suppose you have two NodeList objects (which are arraylike), and you want to merge them into a single array. This can also be done efficiently using the spread operator, combining them and converting them at the same time:

const divs = document.querySelectorAll('div');const paragraphs = document.querySelectorAll('p');const mergedArray = [...divs, ...paragraphs];console.log(mergedArray);  //=> Array of div and p elements

When to Use Which Method

Both Array.from() and the spread operator used widely, but there are a couple subtle differences:

Readability

It may come down to personal preference, but I feel that Array.from() can be more readable, especially when you have relative juniors working on your codebase.

Performance

In some cases, there can be performance differences between these methods, especially when it comes to dealing with large datasets lest we forget that Array.from() is literally designed for this function. In most common use cases, though, any performance differences would be negligible.

Additional Features of Array.from()

This is probably the big one: Array.from() can take a map function as its second argument, allowing for the transformation of elements during conversion. For example:

const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };const anArray = Array.from(arrayLike, (x) => x.toUpperCase());console.log(anArray);  //=> ['A', 'B', 'C']

Challenges with Array‑Like Objects

There are a few aspects of arraylike objects that can present as challenges to developers, particularly those who are a little less experienced:

  • Confusion:

    They look like arrays but don't behave entirely like arrays, leading to confusion, especially for beginners.
  • Limited Functionality:

    Since they don't possess array methods, you need to convert them to arrays for more complex operations, which adds an extra step in development.
  • Performance:

    Converting arraylike objects to arrays can have performance implications, especially with large datasets.

The Wrap‑Up

Arraylike objects in JavaScript are a unique feature that, whilst powerful, can introduce complexity. Understanding their nature, and knowing how to convert them to arrays when necessary is a key skill in JavaScript development.


Categories:

  1. Development
  2. Front‑End Development
  3. Guides
  4. JavaScript
  5. Responsive Development