
What are Array‑Like Objects in JavaScript?

In the world of front‑end development and JavaScript, we developers often encounter structures that resemble arrays, yet aren't true arrays. These are called "array‑like objects", and understanding these unique constructs is crucial for effective JavaScript programming.
What are Array‑Like Objects?
Array‑like objects are objects that have a length property and indexed elements, similar to arrays. However, they lack the array‑specific 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 array‑like 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 array‑like.
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 documentHere, divs is a NodeList, which is an array‑like 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 array‑like 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)); //=> 6Here, 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 array‑like 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, shallow‑copied Array instance from an array‑like 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 array‑like), 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 elementsWhen 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 array‑like 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 array‑like objects to arrays can have performance implications, especially with large datasets.
The Wrap‑Up
Array‑like 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.
Related Articles

Replace Inline Styles in Gatsby with an External CSS File. 
Multi‑Source BFS: Solving the 'Rotting Oranges' Problem. Multi‑Source BFS: Solving the 'Rotting Oranges' Problem

Throttling vs. Debouncing in JavaScript: Managing Event Frequency. Throttling vs. Debouncing in JavaScript: Managing Event Frequency

Controlled vs. Uncontrolled Components in React. Controlled vs. Uncontrolled Components in React

How to Prevent Race Conditions in JavaScript with AbortController. How to Prevent Race Conditions in JavaScript with
AbortController
Removing p Tags from Contentful List Items. Removing
pTags from Contentful List Items
JavaScript Essentials for Freelance Web Developers. JavaScript Essentials for Freelance Web Developers

Why querySelector Returns null in JavaScript. Why
querySelectorReturnsnullin JavaScript
LeetCode: Solving the 'Merge Two Sorted Lists' Problem. LeetCode: Solving the 'Merge Two Sorted Lists' Problem

Using classList in JavaScript: add(), remove(), toggle(), and contains(). Using
classListin JavaScript:add(),remove(),toggle(), andcontains()
Prefix Sums and Hash Maps: Solving 'Subarray Sum Equals K'. Prefix Sums and Hash Maps: Solving 'Subarray Sum Equals K'

Dynamic Sizing with CSS clamp(). Dynamic Sizing with CSS
clamp()