Convert Array-Like Objects Using Array.from in JS

This article explores how JavaScript’s Array.from() method transforms array-like objects into genuine arrays. You will learn what defines an array-like object, the internal mechanism Array.from() uses to perform the conversion, practical implementation examples, and how to utilize its secondary mapping argument for inline element transformation.

What Is an Array-Like Object?

An array-like object is any JavaScript object that meets two specific criteria: 1. It possesses a non-negative integer length property. 2. Its elements are indexed using numeric keys (starting from 0 up to length - 1).

Common examples in JavaScript include the arguments object inside functions, DOM collections like NodeList or HTMLCollection, and custom objects structured with indexed properties. Unlike true arrays, array-like objects do not inherit methods from Array.prototype, such as .map(), .filter(), .reduce(), or .forEach().

The Mechanism of Array.from()

Introduced in ECMAScript 2015 (ES6), Array.from() creates a new, shallow-copied Array instance from an iterable or array-like object.

When applied to an array-like object, Array.from() executes the following internal steps: 1. Reads the length property: It determines the size of the target array by accessing obj.length. If the length is negative, missing, or invalid, it defaults to 0. 2. Iterates through indices: It loops from index 0 up to length - 1. 3. Retrieves values: For each index, it accesses the corresponding property on the object (obj[index]). If an index is missing, it returns undefined. 4. Constructs the array: It populates a newly allocated array with these values and returns it.

Basic Conversion Example

Consider a custom array-like object:

const arrayLike = {
  0: 'apple',
  1: 'banana',
  2: 'cherry',
  length: 3
};

const realArray = Array.from(arrayLike);

console.log(realArray); 
// Output: ['apple', 'banana', 'cherry']
console.log(Array.isArray(realArray)); 
// Output: true

Once converted, full array functionality is available:

realArray.push('dragonfruit');
const upperCase = realArray.map(item => item.toUpperCase());
console.log(upperCase); 
// Output: ['APPLE', 'BANANA', 'CHERRY', 'DRAGONFRUIT']

Handling Missing Indices and Edge Cases

If the length property specifies a number greater than the actual indexed properties present, Array.from() fills the missing slots with undefined:

const sparseObject = {
  0: 'first',
  2: 'third',
  length: 3
};

const result = Array.from(sparseObject);
console.log(result); 
// Output: ['first', undefined, 'third']

If the length property is smaller than the available indices, only elements up to length - 1 are included:

const truncatedObject = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 2
};

console.log(Array.from(truncatedObject)); 
// Output: ['a', 'b']

Using the Built-In Map Function

Array.from() accepts an optional second argument: a mapping function (mapFn). This allows you to transform elements during the array creation process, avoiding the performance overhead of creating an intermediate array before calling .map().

Syntax:

Array.from(arrayLike, (element, index) => { /* transformation */ });

Example:

const numbers = {
  0: 10,
  1: 20,
  2: 30,
  length: 3
};

const doubled = Array.from(numbers, value => value * 2);
console.log(doubled); 
// Output: [20, 40, 60]

You can also use this feature to quickly generate initialized sequences:

const sequence = Array.from({ length: 5 }, (_, index) => index + 1);
console.log(sequence); 
// Output: [1, 2, 3, 4, 5]

Summary

Array.from() bridges the gap between indexed data structures and standard JavaScript arrays. By inspecting the length property and iterating through the sequential keys, it produces a fully functional array, unlocking standard array methods and streamlining data manipulation.