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:

/*
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.