Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differentiating between arrays and "hashes" in Javascript

Tags:

javascript

In order to make the syntax for one of my functions nicer, I need to be able to tell whether a specific parameter is an array or "hash" (which I know are just objects).

Typeof doesn't work, because they both return the same thing

typeof {foo:"bar"} // Object

typeof ["foo","bar"] // Object

So how would I differentiate between the two?

I know this works, but I'm hoping there's a nicer way

({foo:"bar"}).constructor // Object()

(["foo","bar"]).constructor // [ undefined ]

EDIT Ah, it seems [ undefined ] in firebug is the same thing as Array. Kind of weird.

like image 474
Jamie Wong Avatar asked Jul 09 '10 17:07

Jamie Wong


People also ask

What is the difference between hashes and arrays?

With arrays, the key is an integer, whereas hashes support any object as a key. Both arrays and hashes grow as needed to hold new elements. It's more efficient to access array elements, but hashes provide more flexibility.

What is the difference between hash table and array list?

ArrayList is an ordered Collection of objects, the objects will be in the same order that you use to add them to the ArrayList. HashTable is a Collection of Key Value Pair. Each object in the HashTable is defined by a Key and Value. Generally the ArrayList is quicker than the HashTable to insert elements in some cases.

What are hashes in JavaScript?

A hash function is a method or function that takes an item's key as an input, assigns a specific index to that key and returns the index whenever the key is looked up. This operation usually returns the same hash for a given key.

Are there hashes in JavaScript?

There exist two components of Hash tables in JavaScript: an “Object” and a “Hash Function”: Object: An object contains the hash table in which the data is stored. It holds all the “key-value” pairs of the hash table.


2 Answers

You could check the length property as SLaks suggested, but as soon as you pass it a function object you'll be surprised, because it in fact has a length property. Also if the object has a length property defined, you'll get wrong result again.

Your best bet is probably:

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

jQuery uses it, and a "couple of" other people... :)

It is more fail proof than the instanceof way. The method is also suggested by the following article:

'instanceof' considered harmful (or how to write a robust 'isArray') (@kagax)

Another thing to add that this function is almost identical to the Array.isArray function in ES 5 spec:

15.4.3.2 Array.isArray ( arg )

  1. If Type(arg) is not Object, return false.
  2. If the value of the [[Class]] internal property of arg is "Array", then return true.
  3. Return false.
like image 73
25 revs, 4 users 83% Avatar answered Oct 09 '22 10:10

25 revs, 4 users 83%


something instanceof Array works fine within a single document, but will fail if you start passing arrays between different windows, because the Array from one window is a different object from Array on another. If you have no intention of doing cross-window-scripting (and in general, it's worth avoiding) I would recommend sticking with this.

If you need cross-window support, things are a bit more complex. In the future the story is simple, as ECMAScript Fifth Edition defines a function to do exactly this:

Array.isArray([1]);   // -> true

You should use this functionality where available as it's the only reliable and standards-endorsed way. However, many of today's browsers don't support it yet.

Where it isn't available you have to rely on Object#toString serialisation, which is ugly and slightly dodgy. Although it will in general work reliably with today's browsers, there are imaginable cases where it might not (primarily to do with host objects).

You can hack this fallback method into Array on browsers that don't support it, and then use Array.isArray at all times:

if (!('isArray' in Array)) {
    Array.isArray= function(o) {
        return Object.prototype.toString.call(o)==='[object Array]';
    };
}

As for constructor, never use it. It's not available everywhere and it doesn't do what you think. Using it is almost always a mistake.

like image 39
bobince Avatar answered Oct 09 '22 10:10

bobince