RobG said:
I was almost going to recommend the jQuery 'isFunction' function here,
as a joke. e.g. This problem has already been solved. See
jQuery.isFunction.
A javscript function can be defined as an object that implements an
internal [[Call]] method, i.e. that it can be called. The difficulty
is that you can't directly test for that other than actually
attempting to call it. While it is required that native functions
return true for:
typeof functionName === 'function'
Just because something is callable doesn't mean it is a function.
"is a Function" can be roughly translated to Function.prototype is on
the object's prototype chain.
To determine that, instanceof and isPrototypeOf could be used. Except
for frames, because a function in an IFRAME doesn't have the parent
window's Function.prototype in its prototype chain, so a cross-frame
test would fail.
An object that implements [[Call]] isn't necessarily a Function. That's
what David spent many long replies trying to explain to Thomas, who
seemed to not understand the intent of David's isFunction.
The purpose of knowing if something is a function, rather than is
callable, seems to be to know if you can call 'call' or 'apply' directly
on that object.
Fortunately, isFunction isn't necessary and typeof is really all you
need (see below).
there is no such requirement for host objects that can be called. For
example:
alert(typeof document.getElementById);
shows "function" in Firefox and "object" in IE, similarly:
alert( document.getElementById instanceof Function);
returns true in Firefox and false in IE.
So testing with either instanceof or typeof is only suitable if the
object to be tested is known to be a native object.
There is no way to determine if a Host object is callable, other than to
try and call it, though that may result in Error. It would have been
better if the implementations (MSIE) had followed the spirit of the
typeof operator for Host objects. For example, in IE, getElementById is
an object that implements [[Call]].
Function.prototype.call.call(document.getElementById, document, "x");
Works in IE. This could only be possible if either:
A) document.getElementById implements [[Call]].
B) JScript has a special implementation of Function.prototype.call to
handle Host object.
Either way, we can still use the callable check with the typeof operator:
if(typeof x == "function")
Function.prototype.call.call(x, context, "x");
Garrett