Alternative isFunction Implementations (v11)

Revision 11 of this benchmark created by Burakkuhatto on


Description

This test case compares six isFunction implementations, with error checking:

  • isFunctionA checks the internal [[Class]] name of an object to determine if it is a function. Unfortunately, while this check is the most reliable, it's also less efficient due to the extra call to Object#toString.
  • isFunctionB was proposed as an alternative to the typeof and instanceof operators by Garrett Smith. This implementation uses duck-typing, so it may produce incorrect results.
  • isFunctionC was previously used in Underscore.js. This implementation uses only basic duck-typing; thus, it is the most likely to produce incorrect results.
  • isFunctionD instanceof operator
  • isFunctionE typeof function
  • isFunctionF is currently used in Underscore.js as of 10-03-2013

Preparation HTML

<script>
function closure() {
  return function() {
    return 42;
  };
}
  var
      // used in isFunction implementations
      getClass = {}.toString,
      hasProperty = {}.hasOwnProperty,

      // Test data
      noop = function(){},
      objectToString = {}.toString,
      objectHasOwnProperty = {}.hasOwnProperty,
      expression = /Kit/g,
      browserAlert = alert,
      objectConstructor = Object,
      dateConstructor = Date,
      stringConstructor = String,
      int = 12345,
      emptyStr = "",
      longStr = "abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789 abcdefghijklmnopqrstuvwxyz0123456789";
  
  // Checks the internal [[Class]] name of the object.
  function isFunctionA(object) {
   return !!(object && getClass.call(object) == '[object Function]');
  }
  
  // Partial duck-typing implementation by Garrett Smith.
  function isFunctionB(object) {
   if (typeof object != 'function') return false;
   var parent = object.constructor && object.constructor.prototype;
   return parent && hasProperty.call(parent, 'call');
  }
  
  // Pure duck-typing implementation taken from Underscore.js.
  function isFunctionC(object) {
   return !!(object && object.constructor && object.call && object.apply);
  }

  // Simple typeof comparison
  function isFunctionD(object) {
   return typeof(object) == 'function';
  }
  
  // Simple instanceof comparison
  function isFunctionE(object) {
   return object instanceof Function;
  }

  function isFunctionF(object) {
    return object === Object(object);
  }

var toStr = Object.prototype.toString;
  // Object.prototype.toString.call(func)
  function isFunctionF(object) {
   return toStr.call(object) == '[object Function]';
  }
  
  // Checks the internal [[Class]] name of the object.
  // (with strict equality)
  function isFunctionAb(object) {
   return !!(object && getClass.call(object) === '[object Function]');
  }

  // Simple typeof comparison
  // (with strict equality)
  function isFunctionDb(object) {
   return typeof(object) === 'function';
  }

  function benchmarkIsFunction(fnc)
  {
    fnc(noop);
    fnc(objectToString);
    fnc(objectHasOwnProperty);
    fnc(expression);
    fnc(browserAlert);
    fnc(objectConstructor);
    fnc(dateConstructor);
    fnc(stringConstructor);
    fnc(int);
    fnc(emptyStr);
    fnc(longStr);
    fnc(undefined);
    fnc(closure);
  }

  function verify(verified, fnc, name, data)
  {
    if(!verified && typeof console !== "undefined" && typeof console.error !== "undefined")
    {
      console.error(name + " failed the functionality test for data " + data);
    }
  }

  function verifyIsFunction(fnc, name)
  {
    verify(fnc(noop) === true, fnc, name, "noop");
    verify(fnc(objectToString) === true, fnc, name, "objectToString");
    verify(fnc(objectHasOwnProperty) === true, fnc, name, "objectHasOwnProperty");
    verify(fnc(expression) === false, fnc, name, "expression");
    verify(fnc(browserAlert) === true, fnc, name, "browserAlert");
    verify(fnc(objectConstructor) === true, fnc, name, "objectConstructor");
    verify(fnc(dateConstructor) === true, fnc, name, "dateConstructor");
    verify(fnc(stringConstructor) === true, fnc, name, "stringConstructor");
    verify(fnc(int) === false, fnc, name, "int");
    verify(fnc(emptyStr) === false, fnc, name, "emptyStr");
    verify(fnc(longStr) === false, fnc, name, "longStr");
    verify(fnc(undefined) === false, fnc, name, "undefined");
    verify(fnc(closure) === true, fnc, name, "closure");
    verify(fnc(closure()) === true, fnc, name, "closure()");
    verify(fnc(function(){}) === true, fnc, name, "function(){}");
  }

  verifyIsFunction(isFunctionA, "A");
  verifyIsFunction(isFunctionB, "B");
  verifyIsFunction(isFunctionC, "C");
  verifyIsFunction(isFunctionD, "D");
  verifyIsFunction(isFunctionE, "E");
  verifyIsFunction(isFunctionE, "F");
  verifyIsFunction(isFunctionAb, "Ab");
  verifyIsFunction(isFunctionDb, "Db");

</script>

Test runner

Ready to run.

Testing in
TestOps/sec
isFunctionA
benchmarkIsFunction(isFunctionA);
ready
isFunctionB
benchmarkIsFunction(isFunctionB);
ready
isFunctionC
benchmarkIsFunction(isFunctionC);
ready
isFunctionD
benchmarkIsFunction(isFunctionD);
ready
isFunctionE
benchmarkIsFunction(isFunctionE);
ready
isFunctionF
benchmarkIsFunction(isFunctionF);
ready
isFunctionAb
benchmarkIsFunction(isFunctionAb);
ready
isFunctionDb
benchmarkIsFunction(isFunctionDb);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.