jsguides

Array.from()

Array.from(arrayLike, mapFn?, thisArg?)

Array.from() creates a new Array instance from an iterable or an array-like object, optionally running a mapping function on each element along the way. It is a static method on the Array constructor, so you call it as Array.from(...) and not on an existing array. It has been available across browsers since September 2015 (ES2015).

Use it whenever you need to turn something that is not already a real array (a Set, a Map, a NodeList, an arguments object, a string, or any object with a length property) into one. The optional mapFn lets you shape the values during the conversion, which often replaces a two-step Array.from(x).map(fn) pattern with a single pass.

Syntax

Array.from(items)
Array.from(items, mapFn)
Array.from(items, mapFn, thisArg)

Array.from() is a static method, not an instance method. It can also be called on subclasses of Array (or any constructor that accepts a single numeric length), in which case the returned instances belong to that subclass.

Parameters

NameTypeRequiredDescription
itemsiterable or array-likeyesAnything with a Symbol.iterator (strings, Set, Map, generators, etc.) or any object with a length property and integer-keyed entries. If length is undefined or 0, the result is an empty array.
mapFnfunctionnoCalled as mapFn(element, index) for each item. The return value (not the original element) is added to the output array. Equivalent to a .map() pass, but applied during construction so there is no intermediate array.
thisArganynoValue bound to this inside mapFn. Ignored if mapFn is an arrow function.

Defaults

  • mapFn defaults to undefined (no mapping; the original values are kept).
  • thisArg defaults to undefined.

Return value

A new Array instance. It is a shallow copy: nested objects and arrays are shared by reference, not cloned. If Array.from() is called on a subclass of Array (for example MyArray.from(iterable)), the result is an instance of that subclass, not a plain Array.

There are no thrown errors in normal use. The only failure mode is logical: passing a value with no iterator and no length produces an empty array instead of throwing.

Examples

String to an array of code points

Array.from("foo");
// ["f", "o", "o"]

// Safe for surrogate pairs (emoji), unlike "...".split("")
Array.from("😀👍");
// ["😀", "👍"]

Array.from() iterates by code point, so it does not split a surrogate pair into two broken halves. String.prototype.split("") does, which is the main reason to prefer Array.from() (or the spread syntax) for this use case.

Set to a deduplicated array

const set = new Set(["foo", "bar", "baz", "foo"]);
Array.from(set);
// ["foo", "bar", "baz"]

Sets preserve insertion order, so the output array matches the order in which values were first added to the set. This is the most common way to dedupe an existing array: build a Set from it, then call Array.from() to get the unique values back as a real array.

Map to an array of pairs, keys, or values

const map = new Map([[1, 2], [2, 4], [4, 8]]);

Array.from(map);
// [[1, 2], [2, 4], [4, 8]]

Array.from(map.keys());
// [1, 2, 4]

Array.from(map.values());
// [2, 4, 8]

When you call Array.from() on a Map, it iterates the entries as [key, value] pairs. Use map.entries() (or just Array.from(map)) for the same result, or map.keys() and map.values() when you only need one side.

arguments object to a real array

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

f(1, 2, 3);
// [1, 2, 3]

The arguments object inside a function is array-like but lacks Array.prototype methods, so converting it is a common need in older codebases. Modern rest parameters (function f(...args)) remove the need for this, but you will still see Array.from(arguments) in code targeting older runtimes.

NodeList from the DOM, with mapping

const images = document.querySelectorAll("img");
const sources = Array.from(images, (image) => image.src);
// Array of string URLs

Passing mapFn here skips a separate .map() call and avoids iterating a (possibly live) NodeList twice. If the DOM changes between the two passes, the results of .map() may not match the original query, a subtle source of bugs in long-lived pages.

Generate a numeric range

Array.from({ length: 5 }, (_, i) => i);
// [0, 1, 2, 3, 4]

const range = (start, stop, step) =>
  Array.from(
    { length: Math.ceil((stop - start) / step) },
    (_, i) => start + i * step,
  );

range(0, 5, 1);
// [0, 1, 2, 3, 4]
range(1, 10, 2);
// [1, 3, 5, 7, 9]

The first argument is just an object literal with a length; it has no entries of its own, so every slot is undefined until mapFn writes to it.

Double every value

Array.from([1, 2, 3], (x) => x + x);
// [2, 4, 6]

Gotchas

  • length is required on array-like inputs. Array.from({ 0: "a", 1: "b" }) returns [] because length is undefined. Add length: 2 and it works.
  • Sparse arrays become dense. A hole is read as undefined, so Array.from([1, , 3]) returns [1, undefined, 3]. Note the own undefined property, not a missing slot.
  • Shallow copy only. Nested objects are shared by reference. To clone deeply, follow with structuredClone(result).
  • mapFn receives (element, index). Element first, matching Array.prototype.map.
  • thisArg is ignored by arrow functions. Arrow mapFns bind this lexically.
  • Generic factory. Array.from.call(MyArray, iterable) returns MyArray instances. The constructor only needs to accept a single numeric length argument.
  • No IE support. ES2015 only. If you still target IE, you need a polyfill (for example core-js).

See Also