How to check if an object is not an array?

55,378

Solution 1

Try something like this :

obj.constructor.toString().indexOf("Array") != -1

or (even better)

obj instanceof Array

Solution 2

All these answers suggesting that you check to see (one way or another) if an object is an instance of the "Array" class (that is, constructed by "Array") are really not safe solutions. They'll work sometimes, maybe most of the time, but all the major frameworks have moved away from that approach. One of the main problems with it comes about when there's interaction between multiple windows (generally, a parent window and one or more frame or iframe windows). If you pass an array object created in one window into an API resident in another window, all these tests will fail. Why? Because what you're testing is whether an object is an instance of the "Array" class in your local window context. In other words, when you reference "Array" in

if (myobject instanceof Array) { ... }

what you're referencing is window.Array, of course. Well, an array constructed in another window is not going to be an instance of the Array class in your window!

Checking the constructor name is probably a little safer, though it's still risky. In my opinion, you're better off taking a duck-typing approach. That is, instead of asking, "Is this an Array?" ask instead, "does this object seem to support some particular set of Array APIs I need in this circumstance?" For example, "does this object have a length property?" Javascript is a pretty "soft" language, and just about everything's mutable. Thus even if you do find out something was constructed by "Array", you still really don't know for sure what you can do with it or to it.

[edit] Thanks for that link, @Lachlan - here's a very clear description of the issues: http://juhukinners.com/2009/01/11/typeof-considered-useless-or-how-to-write-robust-type-checks/

Solution 3

To test if something is an instance of an Array:

const arr = [1,2,3];
Array.isArray(arr);  // true

To test is something is an instance of an Object:

const obj = { 1: 'a', 2: 'b', 3: 'c' };
obj.constructor === Object;  // true

Note the latter would throw an error if obj is null or undefined, in that case you could use: typeof obj === 'object' or just do a null check: obj && obj.constructor === Object.

Solution 4

To determine whether a given object is an array, ECMAScript 5 introduces the Array.isArray() method, which is currently supported across all modern browsers. Refer to this ECMAScript compatibility table.

To determine the class of a particular object, you can use the Object.prototype.toString() method.

Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call([]); // "[object Array]"

Solution 5

For what it's worth, here is how jQuery checks whether something is an array:

isArray: function( arr ) {
    return !!arr && arr.constructor == Array;
}

But, this article recommends doing it like this:

function isArray(o) {
    return Object.prototype.toString.call(o) === '[object Array]';
}
Share:
55,378

Related videos on Youtube

hojberg
Author by

hojberg

Updated on November 19, 2020

Comments

  • hojberg
    hojberg over 3 years

    So i have a function that needs to check if an argument is an object, but this fails because:

    typeof [] // returns 'object'
    

    This is a classic javascript gotcha, but i cant remember what to do to actually accept objects, but not arrays.

  • hojberg
    hojberg over 14 years
    it seems your first suggestion is the most safe one and would also fix the problem stated by @Pointy below. Thank you :)
  • hojberg
    hojberg over 14 years
    or to be more exact: Object.prototype.toString.call(obj) === '[object Array]';
  • Pointy
    Pointy over 14 years
    Not really a good solution. See juhukinners.com/2009/01/11/…
  • Teja Kantamneni
    Teja Kantamneni over 14 years
    jQuery has a utility method isArray(). api.jquery.com/jQuery.isArray @hojberg I back your way of doing it. jQuery Internally does the same.
  • Joel Mueller
    Joel Mueller almost 8 years
    This approach will fail if obj was created in a different frame. Array.isArray doesn't have that issue if you can target ES5.
  • IliasT
    IliasT about 7 years
    I don't believe this answers the question, which is about detecting if an argument is an object. The asker is pointing out that an array creates a false positive when using typeof. I've posted an updated answer that should handle either case.
  • IliasT
    IliasT over 6 years
    this seems more convoluted than just typeof {} === 'object'
  • IliasT
    IliasT over 6 years
    I would prefer typeof {} or typeof [] to using the prototype's toString method.
  • Pax Beach
    Pax Beach about 6 years
    Tell please, what kind of object exist else? Null, Object (not Array), Object Array... what else are they?
  • Joey Dias
    Joey Dias almost 6 years
    there is a bug in typeof keyword. if you do typeof null that will also return 'object'. this solution is more generic.
  • IliasT
    IliasT almost 6 years
    good point, then I would do something like thing && typeof thing === 'object'
  • png
    png over 4 years
    The "event better" suggestion isn't right const x = []; x instanceof Object // true
  • mrh1997
    mrh1997 about 2 years
    Your link is defekt (I can't say if by accident or by intent)
  • Mike
    Mike about 2 years
    In cases like this, you can use the safe-navigation/optional-chaining operator: obj?.constructor