Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Detecting types in JavaScript sucks

This answer discusses the standard way to check the type of a JavaScript object (specifically, an array):

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!' ); }

Why abuse Object.prototype.toString? It turns out that objects created in different frames have different constructors.

typeof only works for objects which are (or have equivalent) primitives, like strings.

Another way?

The above code makes me feel funny inside, and doesn’t have a chance of working for custom types, so I wrote this [Gist]:

function isType(object, type){
     return object != null && type ? object.constructor.name === type.name : object === type;
}

You use it like this:

isType([1, 2, 3], Array);
isType(null, null);
isType('foo', String);

mauke on ##javascript points out that it fails for objects whose constructors have the same name as the type you're testing against:

isType(new (function String(){}), String);

I think I like this behavior more than calling every custom type an Object.

To take it one step further

jQuery has a 25-line isPlainObject to tell if something is a plain object ({ foo: 'bar' }).

In what cases does the jQuery version behave more-correctly than…

isType(thing, Object);

?

Disclaimer: I haven’t tested this code in a bunch of cases or in a bunch of browsers. The experience concentrated into the jQuery source could blow me back to preschool.

share|improve this question

migrated from stackoverflow.com Oct 10 '11 at 10:26

This question came from our site for professional and enthusiast programmers.

    
One thing to consider: checking to see whether the constructor names are exactly equal (that is, the exact same string) may not work if it's possible for objects to "drift" between frames. That's one of the reasons that the big libraries don't do things like that -- each window has its own separate "Array" constructor, for example, and it's entirely possible that the name "Array" is distinct window by window also. –  Pointy Oct 10 '11 at 4:06
    
I thought constructor property wasn't reliable in a multi window environment too. –  alex Oct 10 '11 at 4:06
    
isType(false, Boolean) –  John Flatness Oct 10 '11 at 4:07
    
@Pointy: Excellent point. In my testing, comparing the names does work across frames (unlike comparing the constructors themselves). Have you had a different experience? –  Sidnicious Oct 10 '11 at 4:11
    
@JohnFlatness: Thanks! Does this edit fix it? –  Sidnicious Oct 10 '11 at 4:13
show 2 more comments

2 Answers 2

I could not find anything wrong with your code, so per Meta I am going to tell you why it is awesome ;)

  • Checking .toString() is icky, toString() could easily be replaced/enhanced
  • Your solution works across frames
  • I was not able to break it.

On a final note, it seems to me that needing to verify the type of an object ( besides assertions ) means you are doing something odd and probably the code should be re-thought.

Still, I am favouriting this question.

UPDATE : Turns out that according to jsperf, your solution is much slower :\

share|improve this answer
add comment

Alright I'm going to focus on some potential errors with your isType function.

The first obvious issue is you're relying on constructor.name being set. This isn't always the case - for instance consider any class declared var MyClass = function() {}. Now if you run (new MyClass).constructor.name === "". Furthermore, many frameworks provide some class extension/constructs such as Mootools which would invalidate that check. Further issues may present themselves with code minification.

Out of curiosity, I decided to plug your code into the underscore js test suite to see how it would do. I couldn't implement _.isObject as it accepts multiple types as objects. It passes all the tests but the ones for NaN understandably. I excluded the iframe tests as I couldn't get them working on gists or jsbin but they pass as well. Not bad :)!

enter image description here

Edit this will also not work for objects created via Object.create unfortunately.

isType(Object.create(null), Object) will throw a TypeError as the resulting object will have no constructor property

Similarly it will fail for any Object that has a constructor property... consider

var obj = {
   constructor: "foo"
};

Edit 2 It appears this also incorrectly? suggests the arguments object is a Object.

(function() {
   isType(arguments, Object) === true;
})([1])
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.