检查一个变量是否为函数类型

1234

假设我有一个变量,其定义如下:

var a = function() {/* Statements */};

我希望有一个函数可以检查变量的类型是否类似于函数。例如:

function foo(v) {if (v is function type?) {/* do something */}};
foo(a);

我如何检查变量 a 是否为上述定义的 Function 类型?


3
这里是一个基准,用于检查最常见的方法:http://jsben.ch/#/e5Ogr - EscapeNetscape
一个内省方法,比如isES3Function,可以检测传入的value是否是在ES3中独有的函数类型,而isGenericFunction则可以检测传入的value是否是一个通用的(或者说不具体/非具体)函数,因此可以是一个传统的ES3函数或者一个非异步箭头函数。 - undefined
如今,功能特定的内省比人们首先想象的要复杂得多。一些情况可以直接解决。无法检测到的情况必须从配置中查找。大多数情况可以通过结合两种方法来推断,应用包括和排除策略。例如,检测一个良好的旧的ES3函数的方式是...它是一个函数类型,具有可写的原型,既不是生成器也不是类。 - undefined
22个回答

2267
if (typeof v === 'function') {
    // do something
}

60
请留意一些内容,例如 typeof Objecttypeof Datetypeof String,它们也都返回 'function'。请注意不要改变原文的意思,并且保证翻译易懂通顺。 - Dave Ward
450
@Dave,我不确定问题出在哪里,因为那些是函数。 - Matthew Crumley
21
if (v instanceOf Function)if (typeof v === 'function')的区别是什么? - mquandalle
15
instanceof 相比,唯一的区别在于如果你正在检查来自另一个文档(可能是 iframe)的函数,则 instanceof 将无法工作。性能有所不同。 - rvighne
16
与被接受的答案不同,这个方法也适用于异步函数。对于一个名为asyncfunctionToCheck的异步函数,getType.toString.call(functionToCheck)==='[object AsyncFunction]',而typeof asyncfunctionToCheck === 'function' - TDreama
显示剩余7条评论

448

虽然underscore的方式更有效率,但当效率不是问题时,检查的最佳方式可以在@Paul Rosania链接的underscore页面上找到。

受underscore的启发,最终的isFunction函数如下:

function isFunction(functionToCheck) {
 return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}

注意:这种解决方案不适用于异步函数、生成器或代理函数。请查看其他答案以获取更为实时的解决方案。


30
根据更新后的性能测试,看起来浏览器的不同会导致巨大的速度差异。在Chrome中,typeof(obj) === 'function' 显然是最快的;然而,在Firefox中,obj instanceof Function 是明显的赢家。 - Justin Warkentin
7
关于这部分内容:“typeof仅应用于检查变量或属性是否未定义。” 在http://javascript.info/tutorial/type-detection的“A good use of typeof”部分和下一部分中,作者指出情况恰好相反。 - Konrad Madej
13
Alex,我很好奇你为什么说 typeof 只应用于检查 undefined。它的名称表明它的目的是检查某个东西的类型,而不仅仅是它是否存在。在使用它进行类型检查时是否存在技术问题或问题?还是更多的是个人偏好?如果有注意事项,最好列出它们,以便其他人可以避免被绊倒。 - jinglesthula
1
我想了解为什么这是最好的选择。另一种方式是否会漏掉某些情况?如果不会,为什么最高性能的解决方案不是最好的选择呢? - František Žiačik
8
请继续向下滚动以找到更简单的解决方案。 - jlh
显示剩余10条评论

196

有多种方法,我将对它们进行总结。

  1. 最好的方法是:
  2. function foo(v) {if (v instanceof Function) {/* do something */} };
    

    最高效的方式(无需字符串比较)并且更为优雅的解决方案——instanceof 运算符在浏览器中已经被支持了很长时间,所以不用担心——它能在 IE 6 中正常工作。

  3. 下一个最好的方法是:

    function foo(v) {if (typeof v === "function") {/* do something */} };
    

    typeof 的缺点是容易出现无声失败,如果您有拼写错误(例如“finction”),那么if语句将只返回false,并且直到代码的后面才会发现错误。

  4. 下一个最好的方法是:
  5. function isFunction(functionToCheck) {
        var getType = {};
        return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
    }
    

    这个方案与解决方案#1或#2相比没有任何优势,但可读性要差得多。改进版如下:

    function isFunction(x) {
        return Object.prototype.toString.call(x) == '[object Function]';
    }
    

    但仍然比解决方案#1缺乏语义。


16
如果将函数传递到不同的框架上下文,则第一个解决方案会失败。例如,从iframe中top.Function !== Function。为确保正确性,请使用第二个解决方案(在调试期间,任何对“function”的错误拼写都将得到纠正,希望如此)。 - MaxArt
4
关于您提到的错别字问题:任何存在这种错别字的代码都很可能很快失败/与基于错别字的其他错误一样不易察觉。使用 typeof === "function" 是最干净的解决方案。此外,您所谓的“最佳”解决方案并未考虑多个全局变量的情况,比如跨帧检查,并且可能会返回假负结果。 - brainkim
笔误的故事只是为了提到魔术字符串的危害性。在可以避免使用魔术字符串的情况下,请尽量避免使用它们。 - ThaJay

144

1
Underscore的版本在大多数浏览器中快得多。请参见:http://jsperf.com/alternative-isfunction-implementations - Paul Rosania
22
我很喜欢下划线,简单却强大。话虽如此,值得注意的是,这个实现可能会被一个带有那些属性的对象欺骗。 - studgeek
3
我今天早些时候偶然发现了这些性能测试,并在修订版4中添加了验证和更多测试数据 - 请运行它以增加浏览器测试覆盖范围。由于有很多测试,每秒操作次数较慢,但也显示了一种实现差异(打开您的javascript控制台并重新加载页面,可能会记录错误消息)。注意:修订版3添加了isFunctionD(仅基于typeof == "function")- 似乎比Underscore的“快速”版本快得多 - Joel Purra
8
现在这个答案有点误导人,因为Underscore.js现在已经进行到第12版(http://jsperf.com/alternative-isfunction-implementations/12),而不是上面引用的第4版,它测试了替代的`isFunction()`实现。它目前使用的实现方法非常接近[dandean](http://stackoverflow.com/users/374773/dandean)所建议的方法。 - Jonathan Eunice
3
Underscore.js现在使用typeof obj == 'function' || false - Emile Bergeron
显示剩余2条评论

93

jQuery(从版本3.3开始不推荐使用)参考文档

$.isFunction(functionName);

AngularJS 参考文档

angular.isFunction(value);

Lodash 参考文档

_.isFunction(value);

Underscore 参考文献

_.isFunction(object); 

自 Node.js v4.0.0 版本起,已弃用 参考文档

var util = require('util');
util.isFunction(object);

61

@grandecomplex:你的解决方案有很多冗余。如果按照以下方式编写,将会更清晰:

function isFunction(x) {
  return Object.prototype.toString.call(x) == '[object Function]';
}

Object.prototype.toString.call 对于你感兴趣的其他 JavaScript 类型非常有用。你甚至可以检查 null 或 undefined,这使它非常强大。 - Jason Foglia
这个答案需要更多的赞,因为它目前是最准确的。 - Bobby Axe
1
这对于异步函数和生成器函数都不起作用。 - lwdthe1
这对于异步函数和生成器函数都不起作用。 - lwdthe1
@lwdthe1 很好的观点:var f = async () => 5; Object.prototype.toString.call(f) 返回'[object AsyncFunction]'。这并不是荒谬或突如其来的,但值得记住。 - undefined

53

更具浏览器支持并包含异步函数的替代方案可能是:

const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);

然后像这样进行测试:

isFunction(isFunction); //true
isFunction(function(){}); //true
isFunction(()=> {}); //true
isFunction(()=> {return 1}); //true
isFunction(async function asyncFunction(){}); //true
isFunction(Array); //true
isFunction(Date); //true
isFunction(Object); //true
isFunction(Number); //true
isFunction(String); //true
isFunction(Symbol); //true
isFunction({}); //false
isFunction([]); //false
isFunction("function"); //false
isFunction(true); //false
isFunction(1); //false
isFunction("Alireza Dezfoolian"); //false

isFunction(null)或isFunction(undefined)返回null而不是true或false。 - undefined
也就是isFunction('[object Function]')会产生错误的结果 - undefined

52

const foo = function() {};
if (typeof foo === 'function') {
  console.log('is function')
}


1
...而且 (() => (typeof obj === 'function') && doSomething()) 仍然是最快的选项。 - darcher

43
尝试使用instanceof运算符:似乎所有函数都继承自Function类:
// Test data
var f1 = function () { alert("test"); }
var o1 = { Name: "Object_1" };
F_est = function () { };
var o2 = new F_est();

// Results
alert(f1 instanceof Function); // true
alert(o1 instanceof Function); // false
alert(o2 instanceof Function); // false

1
正如其他地方所指出的那样,如果函数来自另一个文档(例如 iframe),则可能会失败,因为每个文档都有自己独立的“Function”。 - snarf

13
另一种简单方法:
var fn = function () {}
if (fn.constructor === Function) {
  // true
} else {
  // false
}

2
如果 fn 未定义,它将抛出一个错误。 - Kamil Orzechowski
fn && fn.constructor === Function 这个怎么样? - Yaroslav Melnichuk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接