jsguides

Array.prototype.isArray()

Array.isArray(value)

Array.isArray() is the definitive way to check if a value is an array in JavaScript. Unlike the typeof operator, which returns "object" for arrays, Array.isArray() returns true specifically for array instances and false for everything else. This method was introduced in ES5 to solve the longstanding problem of array type detection across JavaScript realms.

The method is safe to use on any value including null, undefined, and primitives — it never throws. It checks the internal [[IsArray]] slot of the value, which is set only for genuine arrays and is immune to prototype chain manipulation.

Syntax

Array.isArray(value)

Parameters

ParameterTypeDefaultDescription
valueanyThe value to check

Examples

Basic usage

Array.isArray() cleanly separates arrays from everything else. It returns true for any array — literal, constructed, or subclassed — and false for primitives, plain objects, and null. This one-line check is more reliable than typeof, which cannot tell [] apart from {}.

Array.isArray([]);        // true
Array.isArray([1, 2, 3]); // true
Array.isArray(new Array()); // true

Array.isArray("hello");   // false
Array.isArray({});        // false
Array.isArray(null);     // false
Array.isArray(undefined); // false

Rest parameters and the arguments object are array-like but not arrays. Calling Array.isArray() on them returns false, which is easy to miss when you are passing arguments through to array methods. The example below illustrates this with a rest parameter — args looks iterable and behaves like an array in a for...of loop, but Array.isArray correctly reports false.

Checking function arguments

function logArgs(...args) {
  console.log(Array.isArray(args)); // false - arguments is not an array
  console.log(Array.isArray([...args])); // true - spread creates array
}

logArgs("a", "b", "c");

Using Array.isArray() inside a function lets you guard against accidental misuse. Throwing a clear TypeError early is usually better than letting the runtime fail with a cryptic message later in the call stack. The following example shows a processing function that rejects non-array input before attempting to call .map(), which would otherwise throw a less informative error.

Safe type checking

function processData(data) {
  if (!Array.isArray(data)) {
    throw new TypeError("Expected an array");
  }
  return data.map(x => x * 2);
}

processData([1, 2, 3]); // [2, 4, 6]
processData("not array"); // Throws TypeError

You can also pass Array.isArray directly as a callback to array methods like filter. Since it takes a single argument and returns a boolean, it fits the predicate signature perfectly — no wrapper function needed. The example below uses this technique to pull only the array elements out of a mixed collection in a single line.

Filtering arrays from mixed data

const mixed = [1, "hello", [1, 2], {a: 1}, [3, 4]];

const arrays = mixed.filter(Array.isArray);
console.log(arrays);
// [[1, 2], [3, 4]]

When fetching data from an API, the response shape may not match what you expect. Checking with Array.isArray() before iterating protects your code from runtime errors if the server returns a single object instead of an array. The async function below guards against this by defaulting to an empty array when the response is not what was expected.

Validating API responses

async function fetchUsers() {
  const response = await fetch("/api/users");
  const data = await response.json();
  
  if (!Array.isArray(data)) {
    console.error("Expected array, got:", typeof data);
    return [];
  }
  
  return data;
}

TypeScript benefits from Array.isArray() as a type guard. When you check Array.isArray(items), the compiler narrows items from unknown to any[] inside the if block, letting you call array methods without additional casting. The function below demonstrates this pattern: the forEach call is only legal inside the if branch where TypeScript has narrowed the type.

Type guard in TypeScript

function process(items: unknown) {
  if (Array.isArray(items)) {
    // TypeScript now knows items is an array
    items.forEach(item => console.log(item));
  } else {
    console.log("Not an array:", items);
  }
}

For nested structures like matrices, Array.isArray() can be composed with array methods like every to verify the shape of each element. This is a lightweight alternative to a full recursive schema check when you only need one level of depth.

Checking nested arrays

const matrix = [[1, 2], [3, 4], [5, 6]];
const flat = [1, 2, 3, 4, 5];

const allArrays = matrix.every(Array.isArray);
console.log(allArrays); // true

const allArraysFlat = flat.every(Array.isArray);
console.log(allArraysFlat); // false

The example below illustrates a common mistake: calling every(Array.isArray) on a flat array of primitives. Each element (1, 2, …) is not an array, so every returns false. The check works correctly when the outer array is expected to contain only sub-arrays, but gives the wrong answer when you meant to verify each argument was an array.

Validating function parameters

function sum(...numbers) {
  if (!numbers.every(Array.isArray)) {
    return "All arguments must be numbers";
  }
  return numbers.reduce((a, b) => a + b, 0);
}

console.log(sum([1, 2], [3, 4])); // 10

The typeof operator is the most obvious alternative to Array.isArray(), and it is exactly wrong for this task. Since arrays are objects in JavaScript, typeof [] returns "object" — the same value it returns for {}, null, and new Date(). This is not a flaw in typeof; it reflects the language model where arrays are a subtype of object. Array.isArray() fills the gap that typeof intentionally leaves open.

Why not typeof?

typeof []               // "object" (wrong!)
typeof {}               // "object" (correct)
Array.isArray([])       // true (correct!)

The typeof operator returns "object" for both arrays and plain objects because arrays are a subtype of object in JavaScript. Array.isArray() is the only reliable single-step check.

Another place where typeof and instanceof both fail is when arrays cross JavaScript realms — for example, arrays passed from an iframe or a different module context.

Cross-realm arrays

One subtle case where Array.isArray() is essential is when arrays cross JavaScript realms — for example, arrays passed from an iframe or from a different module context. In cross-realm scenarios, arr instanceof Array can return false even for a genuine array, because each realm has its own Array constructor. Array.isArray() checks the internal [[IsArray]] slot, which works correctly across realms.

// In a browser with iframes:
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;

const arr = new iframeArray();
console.log(arr instanceof Array);       // false (different realm)
console.log(Array.isArray(arr));          // true (cross-realm safe)

This matters when writing utility functions or libraries that accept arrays from untrusted or external sources.

A related distinction is between true arrays and array-like objects — collections with a length property and numeric indices that are not actually arrays.

Array-like objects

Array.isArray() returns false for array-like objects — objects with a length property and numeric indices, but not a real array. Common examples include arguments, NodeList, and TypedArray:

Array.isArray(arguments);         // false
Array.isArray(document.querySelectorAll('p')); // false
Array.isArray(new Uint8Array(4)); // false
Array.isArray(Array.from(arguments)); // true — converted to real array

Subclassing Array creates instances that pass Array.isArray(). This is by design — the internal [[IsArray]] slot is set for any genuine array, including those created by a class that extends Array.

Subclasses

Array.isArray() returns true for instances of Array subclasses. If you extend Array with a custom class, Array.isArray(new MyArray()) returns true, because the internal [[IsArray]] slot is set for any genuine array — including subclass instances. This is consistent with instanceof Array for same-realm subclasses, but unlike instanceof, isArray still works across realms.

Understanding the conditions where this check matters helps you use it effectively. The most important cases are when input comes from an external source — another realm, a third-party library, or user data — where type assumptions are unsafe.

When Array.isArray() matters most

Array.isArray() matters most any time the input might come from another realm, another library, or user-controlled data. In those cases, typeof is too vague and instanceof Array can fail for perfectly valid arrays. Array.isArray() gives you the most direct answer available: whether the value is truly an array according to the engine.

It is also a good habit in validation code because it is safe on every kind of input. You can call it on null, objects, primitives, or proxies without special guards first. That makes it a dependable first check before you decide whether to iterate, destructure, or apply array methods.

See Also