3310

I'm trying to write a function that either accepts a list of strings, or a single string. If it's a string, then I want to convert it to an array with just the one item so I can loop over it without fear of an error.

So how do I check if the variable is an array?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • 8
    I thought you meant to 'check if object is an array', but you want to check if 'object is an array of strings or a single string' specifically. Not sure if you see it? Or is it just me? I was thinking of something more like [this](http://stackoverflow.com/questions/767486/how-do-you-check-if-a-variable-is-an-array-in-javascript?lq=1)... am I the one missing something here? – rr1g0 Jul 23 '15 at 18:23
  • 182
    **TL;DR** - `arr.constructor === Array` is fastest. – Neta Nov 23 '15 at 22:37
  • You had an **important** part of the screenshot cut, above the test, where it's written where did the test occur. [My test](http://i.imgur.com/xxD71n8.png) is very different. – vsync Dec 22 '15 at 15:51
  • 1
    @vsync There's a hyperlink. You guys can run it as much as you like. The screenshot is there just for people that are too lazy to click. – mpen Dec 22 '15 at 18:38
  • 4
    http://jsben.ch/#/QgYAV - a benchmark for the most common ways – EscapeNetscape Oct 24 '16 at 17:34
  • 1
    @Neta and what about `arr instanceof Array`? – Déjà vu Nov 16 '16 at 07:42
  • 1
    @EscapeNetscape Your `prototype` test doesn't actually test anything. – mpen Nov 16 '16 at 17:49
  • 56
    **TL;DR** - Array.[isArray(arr)](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) since ES5; and $.[isArray(arr)](http://api.jquery.com/jquery.isarray/) in jQuery. – Ondra Žižka Dec 19 '16 at 09:55
  • 1
    @sheelpriy > [].constructor === Array // true – Rodrigo Leite Aug 28 '17 at 13:50
  • 1
    how about just `typeof x === "string"` to see if it's a string, and if not you can assume it's an array for your use case – Chris Barr Jan 19 '18 at 14:50
  • 8
    Just bear in mind that if you by any reason overwrite your constructor via prototype that `arr.constructor === Array` test will return false. `Array.isArray(arr)` still returns true though. – ghaschel Feb 23 '18 at 17:44
  • 1
    Watch out @Neta `arr.constructor` approach. Some considerations in [this post](https://stackoverflow.com/a/28467392/1358777) – Alwin Kesler Nov 26 '19 at 21:12

51 Answers51

2054

The method given in the ECMAScript standard to find the class of Object is to use the toString method from Object.prototype.

if(Object.prototype.toString.call(someVar) === '[object Array]') {
    alert('Array!');
}

Or you could use typeof to test if it is a string:

if(typeof someVar === 'string') {
    someVar = [someVar];
}

Or if you're not concerned about performance, you could just do a concat to a new empty Array.

someVar = [].concat(someVar);

There's also the constructor which you can query directly:

if (somevar.constructor.name == "Array") {
    // do something
}

Check out a thorough treatment from T.J. Crowder's blog, as posted in his comment below.

Check out this benchmark to get an idea which method performs better: http://jsben.ch/#/QgYAV

From @Bharath, convert a string to an array using ES6 for the question asked:

const convertStringToArray = (object) => {
   return (typeof object === 'string') ? Array(object) : object
}

Suppose:

let m = 'bla'
let n = ['bla','Meow']
let y = convertStringToArray(m)
let z = convertStringToArray(n)
console.log('check y: '+JSON.stringify(y)) . // check y: ['bla']
console.log('check y: '+JSON.stringify(z)) . // check y: ['bla','Meow']
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user113716
  • 318,772
  • 63
  • 451
  • 440
  • 72
    +1 Yup, `toString` is one of the ways to go. I do a bit of a roundup here: http://blog.niftysnippets.org/2010/09/say-what.html – T.J. Crowder Jan 23 '11 at 18:57
  • 17
    If you don't want to type "[object Array]" use Object.prototype.toString.call( someVar ) === Object.prototype.toString.call( [] ) or make a convenience function to get type if you don't want to type Object.prototype.toString.call – Pramod Mar 15 '13 at 06:15
  • 17
    I use the vanilla Array.isArray which works in 'modern browsers' (that is, IE9+ and everyone else). And for old browser support use the shim from MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray – David Gilbertson Oct 11 '13 at 04:40
  • 28
    Live in the modern world - `Array.isArray(obj)` – mcfedr Nov 12 '15 at 23:53
1564

In modern browsers you can do:

Array.isArray(obj)

(Supported by Chrome 5, Firefox 4.0, Internet Explorer 9, Opera 10.5 and Safari 5)

For backward compatibility you can add the following:

// Only implement if no native implementation is available
if (typeof Array.isArray === 'undefined') {
  Array.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  }
};

If you use jQuery you can use jQuery.isArray(obj) or $.isArray(obj). If you use Underscore.js you can use _.isArray(obj).

If you don't need to detect arrays created in different frames you can also just use instanceof:

obj instanceof Array
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fela
  • 26,730
  • 8
  • 26
  • 24
  • 11
    Here is a [more complete](https://kangax.github.io/compat-table/es5/#Array.isArray) list of browsers that support `Array.isArray` – lightswitch05 Dec 17 '14 at 18:51
  • 28
    @NobleUplift: `instanceof Array` fails if the array is from a different frame because every array from that different frame has a different `Array` constructor and prototype. For compatibility/security reasons, every frame has its own global environment, and this includes global objects. The `Object` global from one frame is different from the `Object` global from another. So too for `Array` globals. [Axel Rauschmayer talks more about this](http://2ality.com/2013/01/categorizing-values.html). – jschoi Sep 22 '18 at 07:45
  • 2
    Note that, as of 2022, this is very well supported (even back many browser versions): https://caniuse.com/?search=isArray And also now the fastest method: http://jsben.ch/QgYAV – Andrew May 20 '22 at 21:54
1321

I would first check if your implementation supports isArray:

if (Array.isArray)
    return Array.isArray(v);

You could also try using the instanceof operator

v instanceof Array
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • 134
    `v instanceof Array` will return false if `v` was created in another frame (`v` is instance of `thatFrame.contentWindow.Array` class). – pepkin88 Jan 03 '12 at 02:08
  • 48
    To be specific: [`Array.isArray`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray) is defined as part of ECMAScript 5/Javascript 1.8.5. – jevon Oct 23 '12 at 05:38
306

jQuery also offers an $.isArray() method:

var a = ["A", "AA", "AAA"];

if($.isArray(a)) {
  alert("a is an array!");
} else {
  alert("a is not an array!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Al Foиce ѫ
  • 4,195
  • 12
  • 39
  • 49
janr
  • 3,664
  • 3
  • 24
  • 36
  • 28
    Just a note, jQuery uses the toString method internally: [GitHub Source](https://github.com/jquery/jquery/blob/cd4e25e991898bf07ce82fe4ab3d60c32b4a5fc9/test/libs/require.js#L45-L47) – Jacob Squires Apr 17 '14 at 01:25
111

This is the fastest among all methods (all browsers supported):

function isArray(obj){
    return !!obj && obj.constructor === Array;
}
shinobi
  • 2,511
  • 1
  • 19
  • 27
53

Imagine you have this array below:

var arr = [1,2,3,4,5];

JavaScript (new and older browsers):

function isArray(arr) {
  return arr.constructor.toString().indexOf("Array") > -1;
}

or

function isArray(arr) {
  return arr instanceof Array;
}

or

function isArray(arr) {
  return Object.prototype.toString.call(arr) === '[object Array]';
}

Then call it like this:

isArray(arr);

JavaScript (Internet Explorer 9+, Chrome 5+, Firefox 4+, Safari 5+, and Opera 10.5+)

Array.isArray(arr);

jQuery:

$.isArray(arr);

Angular:

angular.isArray(arr);

Underscore.js and Lodash:

_.isArray(arr);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alireza
  • 100,211
  • 27
  • 269
  • 172
35

Array.isArray works fast, but it isn't supported by all versions of browsers.

So you could make an exception for others and use a universal method:

    Utils = {};
    Utils.isArray = ('isArray' in Array) ?
        Array.isArray :
        function (value) {
            return Object.prototype.toString.call(value) === '[object Array]';
        }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CruorVult
  • 823
  • 1
  • 9
  • 17
  • Array.isArray is pretty much supported by all modern browsers now https://caniuse.com/?search=isArray – jbobbins Sep 08 '22 at 15:24
32

A simple function to check this:

function isArray(object)
{
    return object.constructor === Array;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 17
    I'd reduce that down to one line `return object.constructor === Array` -- but are you sure that this will only return true for arrays? – mpen Sep 04 '12 at 18:39
  • 13
    Can do that with all boolean expressions. Drives me nuts when I see `if(x) return true; else return false` :-) Even if it's backwards, you should negate the expression. – mpen Sep 04 '12 at 18:52
  • 8
    This fails badly if object is undefined or null. – John Henckel Mar 20 '15 at 15:58
26

You can use Array.isArray(). Here is a polyfill:

if (Array.isArray == null) {
  Array.isArray = (arr) => Object.prototype.toString.call(arr) === "[object Array]"
}
Safareli
  • 842
  • 10
  • 18
  • Can you elaborate a little bit? E.g., why is "Array.isArray" on both sides of the "="? "Array.isArray" is a method. What is the principle of operation? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/15219005/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Aug 12 '21 at 20:26
21

As MDN says in here:

use Array.isArray or Object.prototype.toString.call to differentiate regular objects from arrays

Like this:

  • Object.prototype.toString.call(arr) === '[object Array]', or

  • Array.isArray(arr)

ajax333221
  • 11,436
  • 16
  • 61
  • 95
21

There's just one line solution for this question

x instanceof Array

where x is the variable it will return true if x is an array and false if it is not.

Vikash Kumar
  • 1,712
  • 1
  • 11
  • 17
18

I would make a function to test the type of object you are dealing with...

function whatAmI(me){ return Object.prototype.toString.call(me).split(/\W/)[2]; }

// tests
console.log(
  whatAmI(["aiming","@"]),
  whatAmI({living:4,breathing:4}),
  whatAmI(function(ing){ return ing+" to the global window" }),
  whatAmI("going to do with you?")
);

// output: Array Object Function String

then you can write a simple if statement...

if(whatAmI(myVar) === "Array"){
    // do array stuff
} else { // could also check `if(whatAmI(myVar) === "String")` here to be sure
    // do string stuff
}
Al Foиce ѫ
  • 4,195
  • 12
  • 39
  • 49
Billy Moon
  • 57,113
  • 24
  • 136
  • 237
16

You can check the type of your variable whether it is an array with;

var myArray=[];

if(myArray instanceof Array)
{
....
}
Ahmet DAL
  • 4,445
  • 9
  • 47
  • 71
  • 2
    A few people have already mentioned `instanceof`.. I think it fails under a few weird scenarios. – mpen Jan 15 '13 at 16:30
14

I do this in a very simple way. It works for me.

Array.prototype.isArray = true;

a=[]; b={};
a.isArray  // true
b.isArray  // (undefined -> false)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rsbkk
  • 245
  • 3
  • 2
13

This is my attempt to improve on this answer taking into account the comments:

var isArray = myArray && myArray.constructor === Array;

It gets rid of the if/else, and accounts for the possibility of the array being null or undefined

Community
  • 1
  • 1
Dexygen
  • 12,287
  • 13
  • 80
  • 147
12

I know, that people are looking for some kind of raw JavaScript approach. But if you want think less about it, take a look at Underscore.js' isArray:

_.isArray(object)

It returns true if object is an Array.

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eugene
  • 2,226
  • 1
  • 14
  • 15
12

I have updated the jsperf fiddle with two alternative methods as well as error checking.

It turns out that the method defining a constant value in the 'Object' and 'Array' prototypes is faster than any of the other methods. It is a somewhat surprising result.

/* Initialisation */
Object.prototype.isArray = function() {
  return false;
};
Array.prototype.isArray = function() {
  return true;
};
Object.prototype._isArray = false;
Array.prototype._isArray = true;

var arr = ["1", "2"];
var noarr = "1";

/* Method 1 (function) */
if (arr.isArray()) document.write("arr is an array according to function<br/>");
if (!noarr.isArray()) document.write("noarr is not an array according to function<br/>");
/* Method 2 (value) - **** FASTEST ***** */
if (arr._isArray) document.write("arr is an array according to member value<br/>");
if (!noarr._isArray) document.write("noarr is not an array according to member value<br/>");

These two methods do not work if the variable takes the undefined value, but they do work if you are certain that they have a value. With regards to checking with performance in mind if a value is an array or a single value, the second method looks like a valid fast method. It is slightly faster than 'instanceof' on Chrome, twice as fast as the second best method in Internet Explorer, Opera and Safari (on my machine).

le_top
  • 445
  • 3
  • 12
12

The best practice is to compare it using constructor, something like this

if(some_variable.constructor === Array){
  // do something
}

You can use other methods too, like typeOf, converting it to a string and then comparing, but comparing it with dataType is always a better approach.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Atishay Jain
  • 1,425
  • 12
  • 22
6

The best solution I've seen is a cross-browser replacement for typeof. Check Angus Croll's solution.

The TL;DR version is below, but the article is a great discussion of the issue so you should read it if you have time.

Object.toType = function(obj) {
    return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
}
// ... and usage:
Object.toType([1,2,3]); //"array" (all browsers)

// or to test...
var shouldBeAnArray = [1,2,3];
if(Object.toType(shouldBeAnArray) === 'array'){/* do stuff */};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Wundes
  • 61
  • 1
  • 2
5

Here's my lazy approach:

if (Array.prototype.array_ === undefined) {
  Array.prototype.array_ = true;
}

// ...

var test = [],
    wat = {};

console.log(test.array_ === true); // true
console.log(wat.array_ === true);  // false

I know it's sacrilege to "mess with" the prototype, but it appears to perform significantly better than the recommended toString method.

Note: A pitfall of this approach is that it wont work across iframe boundaries, but for my use case this is not an issue.

namuol
  • 9,816
  • 6
  • 41
  • 54
  • 1
    its not better in terms of performance anymore, at least on FF30 on Ubuntu 64-bit – test30 Jul 21 '14 at 09:40
  • 2
    fooled by `wat = {array_: true}` objects. – Bergi Aug 07 '15 at 07:18
  • @Bergi: Yes, that should be obvious. If you're setting `obj.array_ = true`, then you're *only fooling yourself*. – namuol Aug 07 '15 at 23:56
  • @namuol: I'm not necessarily fooling myself. Often enough objects are used as dictionaries. Think of a `cache` object to memoize search results which uses the search strings as property keys. What if a user searches for `array_`? Does your object become an array because of that? It's just a bug. – Bergi Aug 08 '15 at 16:15
  • @namuol: Also, this approach would require that all involved parties (including used libraries) can agree that `.array_` is used for tagging arrays. That's really not the case here, `.array` can mean anything. You should at least use a descriptive string, and signal inappropriateness of arbitrary use, e.g. with `.__isArray = true`. – Bergi Aug 08 '15 at 16:19
  • Agreed! Naming is important. This answer was just a quick hack meant to be used "in a vacuum" -- not really meant for use in libraries. – namuol Aug 20 '15 at 21:24
  • Potentially fooled by `JSON.parse(someDataFromElsewhere).items.array_` returning true. – Roy Tinker Dec 19 '16 at 20:55
5

There is a nice example in Stoyan Stefanov's book JavaScript Patterns which is supposed to handle all possible problems as well as use the ECMAScript 5 method Array.isArray().

So here it is:

if (typeof Array.isArray === "undefined") {
    Array.isArray = function (arg) {
        return Object.prototype.toString.call(arg) === "[object Array]";
    };
}

By the way, if you are using jQuery, you can use its method $.isArray().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
5

The following could be used if you know that your object doesn't have a concat method.

var arr = [];
if (typeof arr.concat === 'function') {
    console.log("It's an array");
}
Jan Aagaard
  • 10,940
  • 8
  • 45
  • 80
yesil
  • 697
  • 1
  • 9
  • 19
5

This function will turn almost anything into an array:

function arr(x) {
    if(x === null || x === undefined) {
        return [];
    }
    if(Array.isArray(x)) {
        return x;
    }
    if(isString(x) || isNumber(x)) {
        return [x];
    }
    if(x[Symbol.iterator] !== undefined || x.length !== undefined) {
        return Array.from(x);
    }
    return [x];
}

function isString(x) {
    return Object.prototype.toString.call(x) === "[object String]"
}

function isNumber(x) {
    return Object.prototype.toString.call(x) === "[object Number]"
}

It uses some newer browser features so you may want to polyfill this for maximum support.

Examples:

> arr(null);
[]
> arr(undefined)
[]
> arr(3.14)
[ 3.14 ]
> arr(1/0)
[ Infinity ]
> gen = function*() { yield 1; yield 2; yield 3; }
[Function: gen]
> arr(gen())
[ 1, 2, 3 ]
> arr([4,5,6])
[ 4, 5, 6 ]
> arr("foo")
[ 'foo' ]

N.B. strings will be converted into an array with a single element instead of an array of chars. Delete the isString check if you would prefer it the other way around.

I've used Array.isArray here because it's the most robust and also simplest.

mpen
  • 272,448
  • 266
  • 850
  • 1,236
5

If the only two kinds of values that could be passed to this function are a string or an array of strings, keep it simple and use a typeof check for the string possibility:

function someFunc(arg) {
    var arr = (typeof arg == "string") ? [arg] : arg;
}
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Yeah... that'd work for this scenario, but not in general. Ended up using varargs anyway. :) – mpen Jan 23 '11 at 20:01
5

You could use the isArray method, but I would prefer to check with:

Object.getPrototypeOf(yourvariable) === Array.prototype

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
STEEL
  • 8,955
  • 9
  • 67
  • 89
  • Why would you prefer this? – mpen Feb 28 '18 at 17:36
  • @mpen `Object.getPrototypeOf(yourvariable)` it returns prototype of an Array object. And The code is fastest and safe to rely on. – STEEL Mar 01 '18 at 10:32
  • 1
    It's easy to foil: https://pastebin.com/MP8d5bCE Also, do you have performance tests to back up your "fastest" claim? – mpen Mar 01 '18 at 23:11
5
var a = [], b = {};

console.log(a.constructor.name == "Array");
console.log(b.constructor.name == "Object");
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
  • 1
    Hi, thanks for your answer. Code only answers tend to be overlooked, would you mind adding some explanation to your code? – giraffesyo Dec 30 '19 at 17:12
4
A = [1,2,3]
console.log(A.map == [].map)

In search for the shortest version, here is what I got so far.

Note, there is no perfect function that will always detect all possible combinations. It is better to know all abilities and limitations of your tools than expect a magic tool.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
exebook
  • 32,014
  • 33
  • 141
  • 226
  • 1
    slight derivation of mine `A.map !== undefined` but yeah, that could be slippy road in the world of monkey patchers ;) – dmi3y Mar 31 '13 at 02:47
  • FYI: This doesn't work across iFrames (http://stackoverflow.com/questions/460256/javascript-when-i-pass-array-from-iframe-function-the-array-lose-his-type/460427#460427) – WiredPrairie Oct 27 '13 at 20:48
  • Why does it work? What is the principle of operation? Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/15352516/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Aug 12 '21 at 20:30
4
function isArray(value) {
    if (value) {
        if (typeof value === 'object') {
            return (Object.prototype.toString.call(value) == '[object Array]')
        }
    }
    return false;
}

var ar = ["ff","tt"]
alert(isArray(ar))
RoboTamer
  • 3,474
  • 2
  • 39
  • 43
  • An explanation would be in order. Please respond by [editing (changing) your answer](https://stackoverflow.com/posts/19669468/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Aug 12 '21 at 20:30
4

A simple function for testing if an input value is an array is the following:

function isArray(value)
{
  return Object.prototype.toString.call(value) === '[object Array]';
}

This works cross browser, and with older browsers. This is pulled from T.J. Crowders' blog post

Brad Parks
  • 66,836
  • 64
  • 257
  • 336
4

You can try this:

var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();

arr.constructor.prototype.hasOwnProperty('push') //true

obj.constructor.prototype.hasOwnProperty('push') // false
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
VIJAY P
  • 1,363
  • 1
  • 12
  • 14
4

The easiest and fastest way to check if an Object is an Array or not.

var arr = [];
arr.constructor.name === 'Array'  // Returns true;

or

arr.constructor === Array // Returns true;

Or you can make a utility function:

const isArray = (obj) => !!obj && obj.constructor === Array;

Usage:

isArray(arr); // Returns true
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sheelpriy
  • 1,675
  • 17
  • 28
4

In your case you may use concat method of Array which can accept single objects as well as array (and even combined):

function myFunc(stringOrArray)
{
  var arr = [].concat(stringOrArray);

  console.log(arr);

  arr.forEach(function(item, i)
  {
    console.log(i, "=", item);
  })
}

myFunc("one string");

myFunc(["one string", "second", "third"]);

concat seems to be one of the oldest methods of Array (even IE 5.5 knows it well).

kolyaseg
  • 535
  • 5
  • 13
4

Exotic one

You want to check if the parameter is a string or not - so try

x===x+''

let isStr = x=> x===x+'';

console.log( isStr([]) );
console.log( isStr(["aa","bb"]) );
console.log( isStr("") );
console.log( isStr("abc") );
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
3

Thankfully, ECMAScript 5 introduced Array.isArray() back in December 2009. If for some reason, you are using a version of JavaScript older than ECMAScript 5, please upgrade.

If you insist on it, though, then arrays do have certain properties that differentiate them from any other type. Properties that I haven't seen mentioned in any of the other answers. Let's get into some JavaScript politics.

An array is an object (typeof [] === "object"), but unlike traditional objects, they have a length property (typeof ( {} ).length === "undefined"). null is also an object (typeof null === "object"), but you can't access a property of null because null is not an object.

This is a bug in the specification that goes all the way back to the very beginning of JavaScript, when objects had the type tag 0 and null was represented as a literal null pointer 0x00, which caused the interpreter to confuse it with objects.

Unfortunately, this doesn't account for [] vs. {length:0}. So we must now turn to the prototype chain.

( [] ).__proto__ === Array.prototype && ( [] ).__proto__ !== Object.prototype.

Thus, without Array.isArray(), this is just about the closest we can get:

function is_array(array){
    return array !== null
        && typeof array === "object"
        && array.__proto__ === Array.prototype;
}

[ [], [1,2,3], {length: 0}, {},
  1, 0, Infinity, NaN, "1", "[1,2,3]",
  null, undefined, [null], [undefined], {a:[]},
  [{}], [{length: 0}], [Infinity], [NaN],
  {__proto__: Array.prototype}
].filter(is_array)
// Expected: [ [], [1,2,3], [null], [undefined], [{}], [{length: 0}], [Infinity], [NaN] ]
// Actual:   [ [], [1,2,3], [null], [undefined], [{}], [{length: 0}], [Infinity], [NaN], {__proto__: Array.prototype} ]

The object maliciously designed to look just like an array actually passes the Turing test. However, replacing the prototype chain with the Array prototype chain is enough to make it act just like an array, effectively making it an array.

The only thing in the world that can tell such an object is actually not an array, is Array.isArray(). But for the purposes you would usually be checking if an object is an array, said object should play nice with your code.

Even the behavior when you change the length of the array artificially is the same: if the length is longer than the number of elements in the array, you will have "empty slots" of that special "implicit undefined" type that is somehow distinct from undefined while also being === undefined; the very same type that is the reason we use typeof obj !== "undefined" to avoid throwing a ReferenceError because obj === undefined only doesn't throw an error if obj was explicitly defined as undefined.

a = {__proto__: Array.prototype}; // Array {}
a.push(5)
a // [5]
a.length = 5
a // [5, empty x 4]
b = a.map(n => n*n) // [25, empty x 4]
b.push(undefined)
b.push(undefined)
b // [25, empty x 4, undefined, undefined]
b[1] // undefined
b[1] === b[5] // true
Array.isArray(a) // false
Array.isArray(b) // true

Don't use is_array(), though. It's one thing to reinvent the wheel for learning purposes. It's another thing to do it in production code. Don't even use it as a polyfill. Supporting old JavaScript versions means supporting old browsers means encouraging the use of insecure software means putting the user at risk for malware.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Braden Best
  • 8,830
  • 3
  • 31
  • 43
  • I'd be okay with removing `is_array` from the answer entirely and just replacing it with a brief explanation that checking an object's `__proto__` against `Array.prototype` may distinguish arrays from most "array-disguised objects", but is no substitute for `Array.isArray` because polyfills and NIH syndrome can be dangerous. I'll get to it later if I have time. – Braden Best Aug 18 '21 at 21:33
3

Although there's some solid answers I would prefer a functional approach using a functor. A functor is just a fancy way to say that we will be passing a function to a value. (The suggestions that I've seen are passing values to a function.)

Create a TypeOf helper

const TypeOf = obj => Object.prototype.toString.call(obj).slice(8,-1);

This is similar to typeof, but it now returns Array for [] and Object for {}. I like to think of it as a strict typeof. If you're working on the Gmail application and performance is a concern then you can do something like this.

const TypeOf = obj => (
  Array.isArray(obj)
   ? "array"
    : obj === null // catch null edge case.  typeof null is an object :)
   ? null
    : typeof obj
)

You could stop here and call it a day. However, you could make it a bit more powerful using composition. You get a lot of benefits if you created a TypeBox Functor, again fancy word for passing a function to a value instead of passing a value to a function.

Create TypeBox

const TypeBox = (predicate, defaultValue) => {
  const TypePredicate = value => ({
     value,
     map: cb => predicate(value)
                ? TypePredicate(cb(value))
                : TypePredicate(defaultValue)
  });
  return TypePredicate;
}

There's a lot going on here, but it's very powerful. The TypeBox function uses a closure and returns our Functor. Closures give you access to Lexical_Scope. Think of it as a backpack that holds the things you want access to later.

Create ArrayBox

const ArrayBox = TypeOf(obj => TypeOf(obj) === 'Array' ? obj : [obj]);

ArrayBox is passing our predicate and defaultValue to TypeOf and will be available when we invoke/execute ArrayBox(name it whatever makes sense for your use case).

Now the fun part

If the input is an Array, return it.

ArrayBox(["foo", "bar"]).value; // ['foo', 'bar']

If the input is not an array, return it in one

ArrayBox("foo").value // ["foo"]

What's great about this approach is that it scales, is easy to test, and it uses composition. You can compose the functions in any manner to get the desired result.

There's many other ways we could approach this using Either or monads.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Robby_rob
  • 190
  • 1
  • 11
2

Other methods also exist to check, but I prefer the following method as my best way to check (as you can easily check types of other objects).

> a = [1, 2]
[ 1, 2 ]
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>
> Object.prototype.toString.call([]).slice(8,-1) // best approach
'Array'

Explanation (with simple examples on Node REPL)»

> o = {'ok': 1}
{ ok: 1 }
> a = [1, 2]
[ 1, 2 ]
> typeof o
'object'
> typeof a
'object'
>
> Object.prototype.toString.call(o)
'[object Object]'
> Object.prototype.toString.call(a)
'[object Array]'
>

Object or Array »

> Object.prototype.toString.call(o).slice(8,).replace(/\]$/, '')
'Object'
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>

Null or Undefined »

> Object.prototype.toString.call(undefined).slice(8,).replace(/\]$/, '')
'Undefined'
> Object.prototype.toString.call(null).slice(8,).replace(/\]$/, '')
'Null'
>

String »

> Object.prototype.toString.call('ok').slice(8,).replace(/\]$/, '')
'String'

Number »

> Object.prototype.toString.call(19).slice(8,).replace(/\]$/, '')
'Number'
> Object.prototype.toString.call(19.0).slice(8,).replace(/\]$/, '')
'Number'
> Object.prototype.toString.call(19.7).slice(8,).replace(/\]$/, '')
'Number'
>

I appreciate @mpen's suggestion to use -1 in place of regular expression as follows.

> Object.prototype.toString.call(12).slice(8,-1)
'Number'
>
> Object.prototype.toString.call(12.0).slice(8,-1)
'Number'
>
> Object.prototype.toString.call([]).slice(8,-1)
'Array'
> Object.prototype.toString.call({}).slice(8,-1)
'Object'
>
> Object.prototype.toString.call('').slice(8,-1)
'String'
>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
hygull
  • 8,464
  • 2
  • 43
  • 52
2

I found the shortest answer now:

var x = [1,2,3]
console.log(x.map?1:0)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

Here is a solution that I came up with and have been using for my projects...

function isArray (o) {
    return typeof o === "object" && o.length !== undefined;
}

isArray({}); // false
isArray(1); // false
isArray("str"); // false
isArray(function(){}); // false

isArray([]); // true

The only pitfall is that it will give a false positive if your object happens to have a length property:

isArray({length:0}); // true

If you are okay with that drawback and know your pure objects won't have that property, it's a clean solution and should be faster than the Object.prototype.toString.call method.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sensei_Shoh
  • 689
  • 7
  • 14
1

Use:

var is_array = function (value) {
   return value &&
     typeof value === 'object' &&
     typeof value.length === 'number' &&
     typeof value.splice === 'function' &&
    !(value.propertyIsEnumerable('length'));
};

This function has been taken from "JavaScript: The Good Parts" book, and it works perfect for me.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nas Tika
  • 29
  • 3
0

Since I don't like any Object.prototype-calls, I searched for another solution. Especially because the solutions of ChaosPandion won't always work, and the solution of MidnightTortoise with isArray() doesn't work with arrays coming from the DOM (like getElementsByTagName). And finally I found an easy and cross-browser solution, which probably also would have worked with Netscape 4. ;)

It's just these four lines (checking any object h):

function isArray(h){
    if((h.length!=undefined&&h[0]!=undefined)||(h.length===0&&h[0]===undefined)){
        return true;
    }
    else{ return false; }
}

I already tested these arrays (all return true):

1) array=d.getElementsByName('some_element'); //'some_element' can be a real or unreal element
2) array=[];
3) array=[10];
4) array=new Array();
5) array=new Array();
   array.push("whatever");

Does this work for all cases? Or is there a case where my solution doesn't work?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marcus
  • 1,222
  • 2
  • 13
  • 22
  • 2
    Too many false positives. `isArray(function(){}); // true`, `isArray("foo"); // true`, `isArray({length:0}); // true` – the system Feb 15 '13 at 18:05
  • 2
    ...and a NodeList isn't an Array anyway. – the system Feb 15 '13 at 18:06
  • Thanks for sharing your test results. This is getting my a lot more insight how Javascript works internally. – Marcus Feb 15 '13 at 20:52
  • The usage of charAt just vanished everywhere out of my code. ;) – Marcus Feb 15 '13 at 21:14
  • It turned out that in JS all strings are functions: `alert("foo".constructor);`, and arrays are functions: `var bar=["id","12345"]; alert(bar.constructor);`, or even structures like this: `foobar={"id":"12345"};` which can be proved by `alert(foobar.constructor);`. But the problem is: Some functions are even arrays, e.g. strings are array. ;) – Marcus Feb 15 '13 at 21:47
  • The prove: `"foo"[0] //returns "f"!`, so strings are arrays and `"foo".charAt(0)` is not really needed in Javascript. – Marcus Feb 15 '13 at 21:52
0

You can use this function to get the data type.

var myAr = [1,2];

checkType(myAr);

function checkType(data) {
  if(typeof data ==='object') {
    if(Object.prototype.toString.call(data).indexOf('Array') !== (-1)) {
      return 'array';
    } else {
      return 'object';
    }
  } else {
    return typeof data;
  }
}

if(checkType(myAr) === 'array') {
  console.log('yes, it is an array')
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kamuran Sönecek
  • 3,293
  • 2
  • 30
  • 57
0

You can find with push like below:

function isArray(obj){
   return (typeof obj.push === 'function') ? true : false;
}

var array = new Array();

or

var array = ['a', 'b', 'c'];
console.log(isArray(array));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lalithkumar
  • 3,480
  • 4
  • 24
  • 40
0

There is a difference between checking out its prototype and Array.isArray:

function isArray(obj){
    return Object.getPrototypeOf(obj) === Array.prototype
}

This function will directly check if an obj is an array.

But for this Proxy object:

var arr = [1,2,3]

var proxy = new Proxy(arr,{})

console.log(Array.isArray(proxy)) // true

Array.isArray will take it as Array.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shuai Li
  • 2,426
  • 4
  • 24
  • 43
  • You seem to be implying that your `isArray` function *won't* return true for the Proxy, but that's not the case; they both return `true` for the Proxy (and unproxied arrays) – mpen Dec 13 '18 at 18:13
0

Here's a code snippet that'll explain an important fact of arrays that should be known early on while learning JavaScript (unlike me).

// this functions puts a string inside an array
var stringInsideArray = function(input) {
  if (typeof input === 'string') {
    return [input];
  }
  else if (Array.isArray(input)) {
    return input;
  }
  else {
    throw new Error("Input is not a string!");
  }
}

var output = stringInsideArray('hello');
console.log('step one output: ', output); // ["hello"]

// use typeof method to verify output is an object
console.log('step two output: ', typeof output); // object

// use Array.isArray() method to verify output is an array
console.log('step three output: ', Array.isArray(output)); // true

Arrays, are in fact, objects.

Using the typeof operator, the output of stringInsideArray('hello') proves that ["hello"] is really an object. This baffled me for the longest time because I assumed that arrays would be a JavaScript data type...

There are only seven JavaScript data types and arrays are not one of them.

To answer your question, using the Array.isArray() method determines that the output is an array.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
underthecode
  • 116
  • 1
  • 5
  • Just FYI, `[].concat(string)` is kind of a weird way of writing `[string]`. – mpen Feb 06 '19 at 04:04
  • @mpen thanks for letting me know. out of curiosity, how would you write this? – underthecode Feb 06 '19 at 06:38
  • `function toArray(x) { if(x === undefined) return []; if(Array.isArray(x)) return x; return [x]; }` or possibly `[...x]` for the middle case depending on whether or not you expect a new array to be returned. – mpen Feb 06 '19 at 08:22
  • @mpen your solution makes a lot more sense. updating my answer accordingly. thanks! – underthecode Feb 06 '19 at 12:49
  • You're quietly suppressing numbers and other non-string inputs if you write it that way. If you only want to allow strings then you should throw an Error if they don't provide one. The scenario I had in mind would allow arrays of anything. – mpen Feb 06 '19 at 19:34
  • when you say Error, something like this for the else statement? `else { throw "Input is not a string!"; }` – underthecode Feb 07 '19 at 06:01
  • 1
    Yes, but you shouldn't throw bare strings. Try `throw new Error("Input is not a string!")` instead. – mpen Feb 07 '19 at 07:49
0

Array.isArray is the way to go about this. For example:

var arr = ['tuna', 'chicken', 'pb&j'];
var obj = {sandwich: 'tuna', chips: 'cape cod'};

// Returns true
Array.isArray(arr);

// Return false
Array.isArray(obj);

bijayshrestha
  • 149
  • 1
  • 14
0

First you can check console.log(typeof Object).

If the output is object then var {data}=object, i.e., just destructure the object according to the object keys.

And the function can be like this:

const abc = (str1, str2=null) => {
    var result = [];
    result.push(str1);
    result.push(str2);
    return result.join("");
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Souvik Dey
  • 39
  • 3
  • FYI, `typeof []` is "object", `typeof ""` is "string", and `typeof new String('')` is "object". This is not a great way to differentiate. – mpen Jul 29 '19 at 22:41
  • Yeah you are right.i meant to say that console.log(typeof variableName) to get the type of the variable. – Souvik Dey Jul 31 '19 at 07:19
0

// In simple ways

const arr = [1, 2, 3];
const obj = { message: 'nice' };
const str = 'nice';
const empty = null;

console.log(Array.isArray(arr));
console.log(Array.isArray(obj));
console.log(Array.isArray(str));
console.log(Array.isArray(empty));
Force Bolt
  • 1,117
  • 9
  • 9
-1

Here's what I use:

function isArray(input) {
  if (input instanceof Array || Object.prototype.toString.call(input) === '[object Array]') {
        return true;
  } else return false;
}
Ric Flair
  • 387
  • 3
  • 5
-1

You can also check with array's length property. When you will try to access the length property of an array, it will return a number (0 for an empty array) while if you try to access the length property of object it will return undefined.

if(Object.prototype.toString.call(arrayList) === '[object Array]') {
  console.log('Array!');
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-1

Array.isArray(obj) does not give very helpful results. I've created a prototype method of Object that seems to correctly determine whether and object is an array or not.

The only edge case that I know of where it fails is when item in the array is set to undefined.

Object.prototype.isArrayLike = function()
{
    var length = this.length || Object.keys(this).length;
    if (length === 0 || this.constructor.name === "String")
        return false;
    for (i = 0; i < length; i++)
    {
        if (typeof this[i] === "undefined")
            return false;
    }
    return true;
};

var arr = ['aaa', 'bbb', 'ccc', 'ddd'];
var arr1 = {"0":'aaa', "1":'bbb', 2:'ccc', 3:'ddd'};
var arr2 = {"0":'aaa', "a":'bbb', 2:'ccc', 3:'ddd'};
var arr3 = "qwerty";
var arr4 = [];
var arr5 = {0:'aaa', 1:'bbb', 2:'ccc', 3:'ddd'};

console.log("arrayLike:" + arr.isArrayLike());
console.log("Array.isArray(arr):" + Array.isArray(arr));
// arrayLike: true
// Array.isArray(arr): true
console.log("arrayLike1:" + arr1.isArrayLike());
console.log("Array.isArray(arr1):" + Array.isArray(arr1));
// arrayLike1: true
// Array.isArray(arr1): false
console.log("arrayLike2:" + arr2.isArrayLike());
console.log("Array.isArray(arr2):" + Array.isArray(arr2));
// arrayLike2: false
// Array.isArray(arr2): false
console.log("arrayLike3:" + arr3.isArrayLike());
console.log("Array.isArray(arr3):" + Array.isArray(arr3));
// arrayLike3: false
// Array.isArray(arr3): false
console.log("arrayLike4:" + arr4.isArrayLike());
console.log("Array.isArray(arr4):" + Array.isArray(arr4));
// arrayLike4: false
// Array.isArray(arr4): true
console.log("arrayLike5:" + arr5.isArrayLike());
console.log("Array.isArray(arr5):" + Array.isArray(arr5));
// arrayLike5: false
// Array.isArray(arr5): true
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dan Bray
  • 7,242
  • 3
  • 52
  • 70
-4
 var length = 16;                               // Number
 var lastName = "Johnson";                      // String
 var cars = ["Saab", "Volvo", "BMW"];           // Array
 var x = {firstName:"John", lastName:"Doe"};

 Object.prototype.myCheck= function(){
 if (this.constructor === Array){
          alert('array');
        }else if (this.constructor === Object)
       {
         alert('object');
        }else if (this.constructor === Number)
        {
          alert('number');
        }else if (this.constructor === String)
        {
          alert('string');
        }

 }
 cars.myCheck();
 lastName.myCheck();
 length.myCheck();
Gaurav
  • 821
  • 9
  • 11
  • 1
    Why did you make your method a prototype of Object if you aren't going to call it like `cars.myCheck()`? – mpen Jul 08 '15 at 16:37
  • yes mark you are correct it should be cars.myCheck().. updated the answer – Gaurav Jul 09 '15 at 17:25
  • 2
    Still no. If you're making it a prototype method, you should drop the `obj` argument and use `this` inside instead. Also, a function that just alerts isn't of much use to anyone. – mpen Jul 09 '15 at 20:17