views:

248

answers:

4

I've done quite a bit of research into this but it seems that the methods used are inconsistent and varied.

Here are some methods I have used in the past:

/* 1: */  typeof myFunc === 'function'
/* 2: */  myFunc.constructor === Function
/* 3: */  myFunc instanceof Function

As part of my research I had a look at how some well-known libraries accomplished this:

 /* jQuery 1.2.6: */  !!fn && typeof fn != "string" && !fn.nodeName && fn.constructor != Array && /^[\s[]?function/.test( fn + "" )
 /* jQuery 1.3b1: */  toString.call(obj) === "[object Function]"
/* Prototype 1.6: */  typeof object == "function"
      /* YUI 2.6: */  typeof o === 'function'

I'm amazed there are so many different methods beings used, surely a single acceptable test has been agreed upon? And I'm completely clueless as to what the intentions were with jQuery 1.2.6's rendition, looks a bit OTT...

So, my quesiton remains, what is the best* way of testing for a function?

I would also appreciate some insight into some of the above methods, especially jQuery 1.2.6's. (I can see what they're doing, it just seems odd)

[*] By 'best', I mean the most widely accepted cross-browser compatible method.


EDIT: Yes, I know it's been discussed before but I'd still like some discussion on the most effective method. Why are there so many different used methods?

The discussions on SO thus far have only mentioned the typeof operator (mostly) but nobody has hinted at the effectiveness of alternate methods.

A: 

This was discussed already on SO here and here.

buti-oxa
I know, but no discussion has ensued about the different methods available. And, I wouldn't mind some insight into jQuery's bizarre implementation.
J-P
I see that you added your edit I see that you read my links already. Good question.
buti-oxa
+2  A: 

John Resig the developer of jQuery does seem to have made some bizarre choices in the internals of jQuery.

toString.call(obj) === "[object Function]"

looks quite neat but I can't think of any situation where the above would be true where the simple typeof approach would fail but perhaps he knows something the rest of use don't.

typeof o === "function"

I would go with the latter since it has greater clarity, unless you've got strong evidence that it won't work.

AnthonyWJones
There are some cases in IE when you ask if a function is a function... and IE says its an Object (can't recall the exact scenarios) I'm guessing that Resig's choice here might be a workaround for the IE bug.
scunliffe
+1  A: 

Why use strict equality on typeof since both operands are strings? I am overlooking some issue?

Anyway, I would go the simpler way of typeof, which seems like being done for that and is readable. instanceof is readable too, but it seems to insist more on the fact that a function is an object, which might be irrelevant to the problem.

PhiLho
I think the strict equality thing is just about strict compliance rather than being technically sound...
J-P
+5  A: 

The best way to test if an object is a function is typeof myFunc === 'function'. If you are using a library, use that library's function test: jQuery.isFunction(myFunc).

Things can be misreported as functions when using typeof. This is very rare but a library is there to remove these inconsistencies. jQuery working around these issues:

  • Firefox reports function with typeof document.createElement("object")
  • Safari reports function with typeof document.body.childNodes
  • Older versions of Firefox reported regular expressions as functions (this not the case in 3.0).
  • Some IE built in global functions (alert) and some node methods (getAttribute) are reported to be of type "object".

Using instanceof rather than typeof circumvents some of these. For example, document.createElement("object") instanceof Function is false in Firefox.

You can view the birth of the first method in the comments for the original ticket (#3618). The new method is from changeset 5947 and seems to have been invented by Resig to solve IE memory leaks. It's probably slower, but smaller, and cleaner.

There isn't much difference between == and === here in terms of how things work but the strict evaluation is ever so slightly faster and thus preferred.

Borgar
Thank you for your explanation Borgar! :)
J-P