Skip to content
JavaScript js arrays 4 min read

Array.from & Array.of

Array.from() and Array.of() are the two static factory methods introduced in ES2015 for building arrays. Array.from() converts anything iterable or array-like — a Set, a NodeList, a string, even arguments — into a real array, optionally mapping each element along the way. Array.of() exists to fix a long-standing quirk in the Array() constructor. Together they give you predictable, expressive ways to create arrays from sources that aren’t already arrays.

Array.from with iterables

Any value that implements the iterable protocol can be passed straight to Array.from() to produce a shallow-copied array. This is the cleanest way to turn a Set, Map, or string into something you can map, filter, or sort.

const unique = new Set([1, 1, 2, 3, 3]);
const list = Array.from(unique);

console.log(list);
console.log(Array.from("hello"));

Output:

[ 1, 2, 3 ]
[ 'h', 'e', 'l', 'l', 'o' ]

Because strings are iterable, Array.from() splits them by code point rather than UTF-16 code unit, so it handles emoji and other astral characters correctly where String.prototype.split("") would break them apart.

console.log(Array.from("a🎉b"));
console.log("a🎉b".split(""));

Output:

[ 'a', '🎉', 'b' ]
[ 'a', '\ud83c', '\udf89', 'b' ]

Array.from with array-likes

An array-like object has a numeric length property and indexed keys (0, 1, 2, …) but lacks array methods. Classic examples are the arguments object inside a function and DOM collections. Array.from() reads the length and copies each index into a genuine array.

function collect() {
  return Array.from(arguments);
}

console.log(collect("a", "b", "c"));
console.log(Array.from({ length: 3, 0: "x", 1: "y", 2: "z" }));

Output:

[ 'a', 'b', 'c' ]
[ 'x', 'y', 'z' ]

Tip: The spread operator ([...value]) also converts iterables to arrays and is shorter. But spread only works on iterables — it throws on plain array-like objects that lack Symbol.iterator. Array.from() handles both iterables and array-likes, so reach for it when the source is an arguments-style object.

The mapping function

Array.from() accepts an optional second argument: a map function applied to every element as the array is built. This is more efficient than Array.from(x).map(fn) because it avoids creating an intermediate array. A third argument sets this for the callback.

const doubled = Array.from([1, 2, 3], (n) => n * 2);
const squares = Array.from(new Set([2, 4, 6]), (n) => n ** 2);

console.log(doubled);
console.log(squares);

Output:

[ 2, 4, 6 ]
[ 4, 16, 36 ]

The callback receives the value and its index, exactly like Array.map().

Generating ranges and sequences

Combining the length array-like trick with the mapping function gives you a concise way to generate sequences without a manual loop. The classic idiom builds an array of a fixed size and fills it from each index.

// 0..4
const range = Array.from({ length: 5 }, (_, i) => i);

// 1..5
const oneToFive = Array.from({ length: 5 }, (_, i) => i + 1);

// 10, 20, 30
const tens = Array.from({ length: 3 }, (_, i) => (i + 1) * 10);

console.log(range);
console.log(oneToFive);
console.log(tens);

Output:

[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 10, 20, 30 ]

This pattern is the idiomatic JavaScript equivalent of a range() function from other languages.

Converting DOM NodeLists

In the browser, methods like document.querySelectorAll() return a NodeList, which is array-like (and in modern browsers, iterable) but only has a forEach. To use map, filter, or reduce, convert it first.

const items = document.querySelectorAll("li.todo");

const texts = Array.from(items, (li) => li.textContent.trim());
const completed = Array.from(items).filter((li) =>
  li.classList.contains("done"),
);

console.log(texts);
console.log(completed.length);

The inline map function above grabs the text in a single pass, while the second example converts first and then filters.

Array.of versus Array()

The Array() constructor is ambiguous: called with a single number it creates an empty array of that length rather than an array containing that number. Array.of() was added to remove this footgun — it always treats its arguments as elements.

CallResultWhy
Array(3)[ <3 empty items> ]Single number = length
Array.of(3)[ 3 ]Number is an element
Array(1, 2, 3)[ 1, 2, 3 ]Multiple args = elements
Array.of(1, 2, 3)[ 1, 2, 3 ]Same here
console.log(Array(7));
console.log(Array.of(7));
console.log(Array.of(1, 2, 3));

Output:

[ <7 empty items> ]
[ 7 ]
[ 1, 2, 3 ]

Gotcha: A sparse array from Array(7) has length 7 but no actual elements, so Array(7).map(fn) does nothing — map skips empty slots. Use Array.from({ length: 7 }, fn) to generate filled arrays instead.

Best Practices

  • Use Array.from() to convert array-like objects (arguments, older NodeLists) where the spread operator would throw.
  • Prefer the spread operator ([...iterable]) for plain iterables like Set and Map when you don’t need a map function — it’s more concise.
  • Pass the mapping function as the second argument to Array.from() instead of chaining .map(), to avoid an extra intermediate array.
  • Reach for Array.from({ length: n }, (_, i) => ...) to generate ranges and filled sequences.
  • Use Array.of() (or a literal) instead of new Array(n) when an argument might be a single number, to avoid accidentally creating a sparse array.
  • Remember both methods produce a shallow copy — nested objects are shared by reference, not cloned.
Last updated June 1, 2026
Was this helpful?