Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Tuesday, September 11, 2007

Type Detection Revisited

Mikol Graves, recently commented on my Type Detection article showing a novel way to do type detection. Here is his code snippet:

function isTYPE(o) { return (o != null && typeof o == ‘object’ && o.constructor.toString() == TYPE.toString()); }

For each Object type that you care about, for example: Date, Array, Class, to name a few. You simply replace “TYPE” with the appropriate Object name. These examples would produce functions like:

function isArray(o) { return (o != null && typeof o == ‘object’ && o.constructor.toString() == Array.toString()); } function isDate(o) { return (o != null && typeof o == ‘object’ && o.constructor.toString() == Date.toString()); } function isClass(o) { return (o != null && typeof o == ‘object’ && o.constructor.toString() == Class.toString()); }

This is nice, because it gives you a way of detecting all kinds of Meta Object types that you might care about. However, you end up using the same code over and over again. Therefore, I took some time and looked around the different toolkits for various other ways that type detection was being done. I found a snippet of code that I really liked in mootools.v1.11. Here is the code:

/* Section: Core Functions */ /* Function: $defined Returns true if the passed in value/object is defined, that means is not null or undefined. Arguments: obj - object to inspect */ function $defined(obj){ return (obj != undefined); }; /* Function: $type Returns the type of object that matches the element passed in. Arguments: obj - the object to inspect. Example: >var myString = 'hello'; >$type(myString); //returns "string" Returns: 'element' - if obj is a DOM element node 'textnode' - if obj is a DOM text node 'whitespace' - if obj is a DOM whitespace node 'arguments' - if obj is an arguments object 'object' - if obj is an object 'string' - if obj is a string 'number' - if obj is a number 'boolean' - if obj is a boolean 'function' - if obj is a function 'regexp' - if obj is a regular expression 'class' - if obj is a Class. (created with new Class, or the extend of another class). 'collection' - if obj is a native htmlelements collection, such as childNodes, getElementsByTagName .. etc. false - (boolean) if the object is not defined or none of the above. */ function $type(obj){ if (!$defined(obj)) return false; if (obj.htmlElement) return 'element'; var type = typeof obj; if (type == 'object' && obj.nodeName){ switch(obj.nodeType){ case 1: return 'element'; case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; } } if (type == 'object' || type == 'function'){ switch(obj.constructor){ case Array: return 'array'; case RegExp: return 'regexp'; case Class: return 'class'; } if (typeof obj.length == 'number'){ if (obj.item) return 'collection'; if (obj.callee) return 'arguments'; } } return type; };

This was a good foundation for an improvement upon my type detection Functions. The $type Function can detect nearly all of my “isType” Functions straight away and has the power to detect some other important types, such as: arguments, textnode, element, collection, and more. So far, I have only added Date in addition to the types already defined and created an additional Function “isType” which can be used to test the object against a desired type.

We lose, “isAlien” Function and whether the number is finite. However, I never use these anymore, so I do not really need them. So far I believe the benefit of using these Functions will out-weight the loss. Although, I have also found these issues: testing for ‘whitespace’ does not work with IE because IE ignores whitespaces when parsing the DOM; in Opera testing for ‘arguments’ will return ‘array’, because Arguments constructor is Array (go figure). Otherwise, it has worked flawlessly and these issues can be worked around. I put together a test page, to verify the results of the isType Function and checked variations on the most common browsers.

You can download my Type Detection JavaScript file.

posted by Matt Snider at 10:09 pm  

5 Comments »

  1. your test page returned everything false

    i modified your “isType” function to

    function isType(o, type) {
    return type == $type(o);
    }

    Comment by joey — September 12, 2007 @ 2:51 am

  2. Good catch Joey. I was toying with renaming the $type function to $T and accidentally replaced it with $defined. Anyway, it is fixed now, so the test page is working.

    Comment by admin — September 12, 2007 @ 7:49 am

  3. Hi Matt,
    I was using your previous code for Type Detection and recently updated to your new version (good vs brilliant). The isType function fails if I make the following call
    isType(document, ’string’);
    The line where it falis is #64
    case Class: return ‘class’;
    Error Msg: Class is not defined
    I have added a kludge to treat document as a special case but hopefully you know better way.
    Regards,
    ks

    Comment by Karan Sharma — April 9, 2008 @ 4:18 am

  4. Karan,

    Please comment out the line of the Function that has:

    case Class: return ‘class’;

    unless you use Prototype or another JavaScript framework that creates the global ‘Class’ Object. You can also add any number of your own custom Classes after the ‘RegExp’ detection, if you care about their type.

    Comment by Matt Snider — April 9, 2008 @ 9:11 am

  5. Thanks for quick reply. I was really lost as to why there was a case Class. Thank you for the fix and the clarification.

    Comment by Karan Sharma — April 10, 2008 @ 3:49 am

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress