How can I check if an object is an array? [duplicate]
Asked Answered
P

51

3328

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?

Possum answered 23/1, 2011 at 18:53 Comment(12)
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... am I the one missing something here?Totipalmate
TL;DR - arr.constructor === Array is fastest.Parke
You had an important part of the screenshot cut, above the test, where it's written where did the test occur. My test is very different.Ethridge
@Ethridge 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.Possum
jsben.ch/#/QgYAV - a benchmark for the most common waysDehisce
@Parke and what about arr instanceof Array?Kneel
@Dehisce Your prototype test doesn't actually test anything.Possum
TL;DR - Array.isArray(arr) since ES5; and $.isArray(arr) in jQuery.Nonpareil
@sheelpriy > [].constructor === Array // trueArezzo
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 caseAddington
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.Pinero
Watch out @Parke arr.constructor approach. Some considerations in this postHallette
H
1588

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
Hindemith answered 6/1, 2014 at 18:11 Comment(3)
Here is a more complete list of browsers that support Array.isArrayEva
@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.Chlorothiazide
Note that, as of 2022, this is very well supported (even back many browser versions): caniuse.com/?search=isArray And also now the fastest method: jsben.ch/QgYAVTenpins
S
2064

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']
Shortening answered 23/1, 2011 at 18:54 Comment(4)
+1 Yup, toString is one of the ways to go. I do a bit of a roundup here: blog.niftysnippets.org/2010/09/say-what.htmlEpitasis
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.callFemmine
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 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Thumping
Live in the modern world - Array.isArray(obj)Rattling
H
1588

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
Hindemith answered 6/1, 2014 at 18:11 Comment(3)
Here is a more complete list of browsers that support Array.isArrayEva
@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.Chlorothiazide
Note that, as of 2022, this is very well supported (even back many browser versions): caniuse.com/?search=isArray And also now the fastest method: jsben.ch/QgYAVTenpins
P
1322

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
Phalansterian answered 23/1, 2011 at 18:55 Comment(2)
v instanceof Array will return false if v was created in another frame (v is instance of thatFrame.contentWindow.Array class).Amino
To be specific: Array.isArray is defined as part of ECMAScript 5/Javascript 1.8.5.Cymatium
D
307

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>
Doughman answered 2/4, 2012 at 12:15 Comment(1)
Just a note, jQuery uses the toString method internally: GitHub SourceUpkeep
L
111

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

function isArray(obj){
    return !!obj && obj.constructor === Array;
}
Lindesnes answered 6/12, 2015 at 10:12 Comment(0)
L
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);
Lunatic answered 27/12, 2016 at 13:17 Comment(0)
N
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]';
        }
Normy answered 10/12, 2012 at 17:1 Comment(1)
Array.isArray is pretty much supported by all modern browsers now caniuse.com/?search=isArraySclerotomy
V
32

A simple function to check this:

function isArray(object)
{
    return object.constructor === Array;
}
Villein answered 4/9, 2012 at 17:56 Comment(3)
I'd reduce that down to one line return object.constructor === Array -- but are you sure that this will only return true for arrays?Possum
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.Possum
This fails badly if object is undefined or null.Thithia
A
26

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

if (Array.isArray == null) {
  Array.isArray = (arr) => Object.prototype.toString.call(arr) === "[object Array]"
}
Actuate answered 5/3, 2013 at 8:26 Comment(1)
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, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).Upas
M
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)

Municipalize answered 14/9, 2012 at 21:2 Comment(0)
S
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.

Seize answered 8/6, 2017 at 12:48 Comment(0)
D
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
}
Decentralization answered 8/8, 2012 at 13:34 Comment(0)
H
16

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

var myArray=[];

if(myArray instanceof Array)
{
....
}
Hy answered 15/1, 2013 at 8:58 Comment(1)
A few people have already mentioned instanceof.. I think it fails under a few weird scenarios.Possum
G
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)
Grayce answered 4/4, 2015 at 6:58 Comment(2)
fooled by {isArray:true}Idiolect
JSON.parse(someDataFromElsewhere).items.isArray could return true (depending on the data) and break your code.Rodrigues
J
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

Jevons answered 1/4, 2015 at 20:35 Comment(1)
constructor is not available in ES5Helve
G
13

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.

Gibbosity answered 9/2, 2019 at 20:12 Comment(0)
A
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
Amylopectin answered 4/4, 2012 at 0:46 Comment(1)
"Unless another tag for a framework/library is also included, a pure JavaScript answer is expected."Roundabout
H
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).

Hedberg answered 1/8, 2015 at 11:10 Comment(0)
E
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 */};
Encrinite answered 23/3, 2012 at 17:7 Comment(0)
J
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;
}
Jessiajessica answered 23/1, 2011 at 19:51 Comment(1)
Yeah... that'd work for this scenario, but not in general. Ended up using varargs anyway. :)Possum
D
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.

Djebel answered 11/1, 2013 at 8:56 Comment(7)
its not better in terms of performance anymore, at least on FF30 on Ubuntu 64-bitNedanedda
fooled by wat = {array_: true} objects.Idiolect
@Bergi: Yes, that should be obvious. If you're setting obj.array_ = true, then you're only fooling yourself.Djebel
@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.Idiolect
@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.Idiolect
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.Djebel
Potentially fooled by JSON.parse(someDataFromElsewhere).items.array_ returning true.Rodrigues
A
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().

Africa answered 15/12, 2013 at 7:11 Comment(1)
+1: why not just a simple if(!Array.isArray) {... ?Acquiescent
P
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");
}
Pushup answered 24/8, 2016 at 8:2 Comment(1)
This is a good trick, but could be overridden... but most of the times should get the resultLunatic
P
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.

Possum answered 24/10, 2016 at 15:48 Comment(0)
D
5

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
Draughts answered 1/3, 2017 at 9:25 Comment(0)
G
5

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

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

Goosefoot answered 28/2, 2018 at 17:21 Comment(3)
Why would you prefer this?Possum
@Possum Object.getPrototypeOf(yourvariable) it returns prototype of an Array object. And The code is fastest and safe to rely on.Goosefoot
It's easy to foil: pastebin.com/MP8d5bCE Also, do you have performance tests to back up your "fastest" claim?Possum
S
5
var a = [], b = {};

console.log(a.constructor.name == "Array");
console.log(b.constructor.name == "Object");
Seigneur answered 30/12, 2019 at 8:32 Comment(1)
Hi, thanks for your answer. Code only answers tend to be overlooked, would you mind adding some explanation to your code?Yvetteyvon
L
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.

Langelo answered 12/3, 2013 at 2:57 Comment(3)
slight derivation of mine A.map !== undefined but yeah, that could be slippy road in the world of monkey patchers ;)Hydranth
FYI: This doesn't work across iFrames (#460756)Azotic
Why does it work? What is the principle of operation? Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).Upas
T
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))
Tervalent answered 29/10, 2013 at 21:26 Comment(1)
An explanation would be in order. Please respond by editing (changing) your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).Upas
O
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

Overcasting answered 2/2, 2014 at 0:29 Comment(0)
P
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
Packard answered 25/2, 2016 at 5:52 Comment(0)
D
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).

Durand answered 15/9, 2017 at 9:41 Comment(0)
S
4

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.

Schutzstaffel answered 3/10, 2019 at 16:47 Comment(0)
R
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") );
Rhadamanthus answered 10/6, 2020 at 14:29 Comment(1)
Cool, so if not isStr does not mean is Array... nice play with a syntax however.Timecard
G
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.

Gobbler answered 19/7, 2018 at 19:12 Comment(1)
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.Gobbler
C
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'
>
Caprine answered 12/10, 2018 at 6:31 Comment(2)
You might as well use -1 as the 2nd arg to slice and save the regex for a rainy day.Possum
Thanks @mpen. I have added your suggestions.Caprine
C
2

I found the shortest answer now:

var x = [1,2,3]
console.log(x.map?1:0)
Crafty answered 23/4, 2019 at 13:1 Comment(1)
why ? 1 : 0 if you're going for the shortest answer, why not !!x.map or even just x.map?Izak
P
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.

Picasso answered 6/4, 2015 at 4:37 Comment(2)
isArray( new String() ); returns trueInterloper
Yes, I noted that as a pitfall in my comments below the examples: "The only pitfall is that it will give a false positive if your object happens to have a length property"Picasso
G
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.

Gangboard answered 13/4, 2015 at 12:53 Comment(1)
var object = {splice: function(){}}; Object.defineProperty(object, "length", {value: 1, enumerable: false}); console.log(is_array(object));Roundabout
D
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?

Danialdaniala answered 12/2, 2013 at 11:3 Comment(6)
Too many false positives. isArray(function(){}); // true, isArray("foo"); // true, isArray({length:0}); // trueJanniejanos
...and a NodeList isn't an Array anyway.Janniejanos
Thanks for sharing your test results. This is getting my a lot more insight how Javascript works internally.Danialdaniala
The usage of charAt just vanished everywhere out of my code. ;)Danialdaniala
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. ;)Danialdaniala
The prove: "foo"[0] //returns "f"!, so strings are arrays and "foo".charAt(0) is not really needed in Javascript.Danialdaniala
C
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')
};
Curtin answered 25/2, 2016 at 9:10 Comment(1)
All the op asked for was a simple efficient check.Dejecta
M
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));
Molech answered 5/6, 2017 at 11:52 Comment(0)
A
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.

Alurd answered 13/12, 2018 at 7:16 Comment(1)
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)Possum
L
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.

Labourer answered 4/2, 2019 at 19:29 Comment(7)
Just FYI, [].concat(string) is kind of a weird way of writing [string].Possum
@Possum thanks for letting me know. out of curiosity, how would you write this?Labourer
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.Possum
@Possum your solution makes a lot more sense. updating my answer accordingly. thanks!Labourer
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.Possum
when you say Error, something like this for the else statement? else { throw "Input is not a string!"; }Labourer
Yes, but you shouldn't throw bare strings. Try throw new Error("Input is not a string!") instead.Possum
C
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);

Chokeberry answered 15/7, 2019 at 18:38 Comment(0)
I
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("");
}
Inward answered 28/7, 2019 at 13:6 Comment(2)
FYI, typeof [] is "object", typeof "" is "string", and typeof new String('') is "object". This is not a great way to differentiate.Possum
Yeah you are right.i meant to say that console.log(typeof variableName) to get the type of the variable.Inward
S
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));
Shemikashemite answered 3/5, 2021 at 13:43 Comment(1)
Isn't Array.isArray covered by previous answers?Upas
M
-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;
}
Melodie answered 5/5, 2018 at 19:7 Comment(0)
A
-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!');
}
Aldaaldan answered 27/9, 2018 at 5:45 Comment(3)
Your paragraph and code example don't align. Also, objects can have a .length property.Possum
You can't check object length. Can u give me a example of object's length propertyAldaaldan
{length:5} boom. an object with a length property.Possum
W
-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
Wachter answered 25/10, 2020 at 1:28 Comment(0)
A
-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();
Arms answered 8/7, 2015 at 12:18 Comment(3)
Why did you make your method a prototype of Object if you aren't going to call it like cars.myCheck()?Possum
yes mark you are correct it should be cars.myCheck().. updated the answerArms
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.Possum

© 2022 - 2024 — McMap. All rights reserved.