Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #11492 (new enhancement)

Opened 2 months ago

Last modified 1 month ago

[PATCH] More robust Object.isFunction

Reported by: kangax Assigned to: kangax
Priority: normal Milestone: 2.x
Component: Prototype Version: edge
Severity: normal Keywords:
Cc:

Description

function isFunction(o) {
  if(typeof fn != "function") return false;
  if(typeof fn.constructor != "function") return false;
  return fn.constructor.prototype.hasOwnProperty( "call" );
}

function isFunctionProto(object) {
  return typeof object == "function";
}

isFunction(/a/); // false
isFunctionProto(/a/); // true

isFunction(Element); // false
isFunctionProto(Element); // true

isFunction(Function('foo', 'return foo;')); // false
isFunctionProto(Function('foo', 'return foo;')); // true

Attachments

0011-patch-for-isFunction.patch (0.7 kB) - added by kangax on 04/12/08 21:04:40.

Change History

04/12/08 21:04:12 changed by kangax

Just to clarify, Object.isFunction currently returns wrong results for regular expressions, most of the host functions in IE and NodeList's in Safari:

Object.isFunction(/foo/); // => true (regexp)
Object.isFunction(window.alert); // => false in IE (host function)
Object.isFunction(document.links); // => true in Safari (HTMLCollection)

The proposed function "fixes" regexp and NodeList glitches, but still returns false for host fucntions in IE

04/12/08 21:04:40 changed by kangax

  • attachment 0011-patch-for-isFunction.patch added.

04/12/08 21:04:57 changed by kangax

  • summary changed from More robust Object.isFunction to [PATCH] More robust Object.isFunction.

04/13/08 00:19:25 changed by jdalton

I dig it but you could make it smaller by:

isFunction: function(object) {  
  if (typeof object != 'function' ||
    typeof object.constructor != 'function') return false;  
  return Object.prototype.hasOwnProperty.call(object,'call');  
}

I don't know if the Object.prototype.hasOwnProperty.call route is better then the object.constructor.prototype.hasOwnProperty('call'),
the both take up the same amount of space.

04/13/08 02:23:00 changed by kangax

Actually, it would get even more verbose : )

test = Function(); // instantiate a function

test.constructor.prototype.hasOwnProperty('call'); // => true
Object.prototype.hasOwnProperty.call(test, 'call'); // => false

afaik, functions don't have "call", but use the one from their prototype chain (i.e. Function.prototype). Invoking Object.prototype.hasOwnProperty in a context of a function obviously yields false.

What's funny here, is that we can't really trust hasOwnProperty of .constructor.prototype (i.e. it could have been augmented or assigned something else). Instead, we can call "original" Object.prototype.hasOwnProperty with the context of object's ".constructor.prototype" - but that's, imho, quite retarded.

// omg bbq wtf!
Object.prototype.hasOwnProperty.call(object.constructor.prototype, 'call');