Okay, my syntax has changed a bit, but see my "improved" function
below. It passes all the jQuery test cases and the additional test
cases from the article on "DHTML Kitchen". It's a little bit weird and
could surely stand to be improved, so go ahead and critique all you
want! I've tested it in IE6, FF2, and Safari3 on Windows. That's all I
have access to at the moment.
Feel free to disregard any of my comments. In the original code my
comments marked as // # (with number sign)
Besides the commented changes I just extra broke some long strings
exclusively for the Usenet post to try to avoid code-smashing wraps.
var isFunction = (function() {
// # conditional compilation needs a condition;
// # also once turned on it is highly suggested
// # to turn it off by the end.
// #
// # JScript pragma commands structure adjusted.
/*@cc_on @*/
/*@if (@_jscript)
// IE reports some element node methods as objects,
// but when converted to string they always have
// the text 'function' and '[native code]' in them
// when they are actually functions.
// Anything reported as typeof=='function' is always
// a function (AFAIK).
return function(o) {
if (typeof o=='function') {
return true;
}
// # if - else if - else, no pending 'if'
// # Not an error but if it's for public
// # attention then let's be accurate ;-)
else if (typeof o=='object') {
// # On IE for DOM elements implicit toString call
// # returns either "function ..." or "[object]"
// # or "unknown" (for some external ActiveX controls):
// # so the 2nd check adds absolutely nothing to the job:
// # /\[native code\]/.test(o) removed
// #
// # At the same time for JScript objects toString
// # method is often overloaded, say to return empty
// # string to prevent source dump.
// # Because the problem affects only DOM elements
// # and because DOM elements are strictly separate
// # from JScript objects in IE then to secure ourselves
// # from overloaded toString and from unnecessary checks:
return Object.prototype.isPrototypeOf(o) ?
typeof o : /^function/.test(o);
}
}
@else @*/
// For other browsers, we're going to build a function
// as a string and only add the tests that are actually
// required by the browser to overcome bugs/quirks.
// # nodeName block further down is optimized to
// # avoid intermediary var assignment: o2 declaration
// # removed.
var func = "if(typeof o !='function') { return false; }\n";
// Check for Firefox because it says
// document.createElement("object")=='function'
// If the object has a nodeName property
// (looks like an element node), then try to create
// a new element of the same type to see if it is typeof=='function'.
// If so, we can conclude that the original object was an element,
// not a real function
// #
// # The bug is exposed for APPLET and OBJECT to be exact.
// #
// # As you check for document.createElement method on
// # method construction then there is no need to re-check
// # it on each method call: nobody will steal it from you
if (document.createElement &&
typeof document.createElement('object')=='function') {
func+= "if (o.nodeName && " +
"typeof document.createElement(o.nodeName)=='function')" +
"{ return false; }\n";
}
// Firefox reports RegExp objects as 'function'
if (typeof new RegExp=='function') {
// * If you want to know about RegExp instances
// * then check for RegExp instances! JavaScript
// * maybe not C++ but at the same time not some
// * GBASIC to spit on OOP completely ;-)
func += "if (RegExp.prototype.isPrototypeOf(o))"+
"{ return false; }\n";
}
// Safari reports NodeList objects as 'function'
// # document.images or document.forms are not NodeList
// # but HTMLCollection. NodeList would be from say
// # document.getElementsByTagName(tname). The principal
// # differences are read-only, no update on iteration
// # for HTMLCollection.
// # Is document.getElementsByTagName('IMG') also
// # reported as "function" by Safari?
if (document.images && typeof document.images=='function' &&
/\[object HTMLCollection\]/.test(document.images) ) {
func += "if (/\[object/.test(o)) { return false; }\n";
}
// The default case - if it says it's a function,
// trust it
func += "return true;\n";
return Function("o",func);
// # Switch pragma reader off:
/*@end @*/
})();