检查变量是否为函数类型


902

假设我有任何变量,定义如下:

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

我想要一个可以检查变量类型是否类似于函数的函数。即:

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

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


Answers:


380

当然,下划线的方法效率更高,但是当效率不是问题时,最好的检查方法是写在@Paul Rosania链接的下划线页面上。

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

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

1
可能有人对此事进行了更广泛的研究,但使用简单的“结果验证”来查看jsperf修订版4的结果isFunctionA显示了与其他方法相比的实现差异。
乔尔·普拉

24
通过更新的性能测试,看起来速度差异很大,具体取决于您的浏览器。在Chrome typeof(obj) === 'function'中,到目前为止看来是最快的。但是,Firefox obj instanceof Function无疑是赢家。
贾斯汀·沃肯汀

7
关于零件:typeof仅应用于检查变量或属性是否未定义。作者指出,在javascript.info/tutorial/type-detection中的typeof的良好使用以及以下内容中,情况恰恰相反
Konrad Madej

11
亚历克斯,我很好奇为什么你说typeof应该只用于检查未定义的。顾名思义,它的目的是检查某物的类型,而不仅仅是检查它是否存在。使用它进行类型检查时是否会出现技术问题或问题,还是更偏爱它?如果有警告,最好将它们列出,这样其他人可以避免绊倒他们。
jinglesthula 2014年

14
过分复杂的解决方案
Daniel Garmoshka '17

1709
if (typeof v === "function") {
    // do something
}

44
只要留意喜欢的几件事typeof Objecttypeof Datetypeof String,而这一切的回报'function'了。
戴夫·沃德

358
@Dave,我不确定是什么问题,因为这些是函数。
马修·克鲁姆利

6
有什么区别if (v instanceOf Function)
mquandalle 2013年

10
@mquandalle没什么大不同,除了instanceof如果您正在检查来自另一个文档(可能是iframe)的功能,则不会起作用。性能各不相同。
rvighne 2014年

8
与公认的答案不同,这也适用于异步功能。对于asyncfunctionToCheckgetType.toString.call(functionToCheck)==='[object AsyncFunction]'typeof asyncfunctionToCheck === 'function'
TDreama '17

132

Underscore.js使用更精细但性能更高的测试:

_.isFunction = function(obj) {
  return !!(obj && obj.constructor && obj.call && obj.apply);
};

请参阅:http//jsperf.com/alternative-isfunction-implementations

编辑:更新的测试表明typeof可能更快,请参阅http://jsperf.com/alternative-isfunction-implementations/4


有什么特别的理由要使用这种方法typof呢?
sv_in 2011年

1
在大多数浏览器中,Underscore的版本快得多。参见:jsperf.com/alternative-isfunction-implementations
Paul

13
我肯定喜欢下划线,简单但功能强大。也就是说,可能值得注意的是,此实现可能被具有这些属性的对象欺骗。
studgeek 2011年

3
@PaulRosania今天早些时候偶然发现了这些性能测试,并通过验证和更多测试数据将其更新为修订版4-请运行它以增加浏览器测试的覆盖范围。每秒的操作速度较慢(由于进行了许多测试),但是它也显示出一种实现方式的差异(打开您的JavaScript控制台并重新加载页面,可能会记录错误消息)。注意:修订版3添加了isFunctionD(仅基于typeof == "function")-它似乎比Underscore的“快速”版本快得多
乔尔·普拉

6
这个答案现在有点误导了,因为Underscore.js现在处于版本12而不是上面引用的版本4的替代isFunction()实现测试中。目前,它所使用的内容与丹丹所建议的非常接近。
乔纳森·尤妮丝

112

有几种方法,所以我将全部总结

  1. 最好的方法是:
    函数foo(v){if(v instanceof Function){/ *做某事* /}};
    
    
    性能最佳(无字符串比较)和优雅的解决方案-很长时间以来,浏览器就一直支持instanceof运算符,因此请放心-它可以在IE 6中运行。
  2. 下一个最佳方法是:
    函数foo(v){if(typeof v ===“ function”){/ *做某事* /}};
    
    
    的缺点typeof是它很容易出现无声故障,很糟糕,因此,如果您有错字(例如“ finction”),在这种情况下,如果if会返回false,直到稍后才会知道您有错误。您的代码
  3. 下一个最佳方法是:
    函数isFunction(functionToCheck){
        var getType = {};
        返回functionToCheck && getType.toString.call(functionToCheck)==='[对象函数]';
    }
    
    
    与解决方案1或解决方案2相比,这没有优势,但可读性差很多。对此的改进版本是
    函数isFunction(x){
        return Object.prototype.toString.call(x)=='[对象功能]';
    }
    
    
    但语义仍然比解决方案#1少很多

10
如果将函数传递到其他框架上下文,则第一种解决方案将失败。例如,来自iframe top.Function !== Function。可以肯定的是,请使用第二种方法(希望在调试过程中纠正“功能”的任何拼写错误)。
MaxArt 2014年

关于错别字的观点:带有错字的任何代码都可能很快失败/不会比其他基于错字的错误更明显。typeof ===“ function”是最干净的解决方案。此外,您使用的“最佳”解决方案instanceof不考虑多个全局变量(例如跨帧检查),并且可能返回假阴性。
brainkim

84

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

$.isFunction(functionName);

AngularJS 参考

angular.isFunction(value);

Lodash 参考

_.isFunction(value);

下划线 参考

_.isFunction(object); 

自v4.0.0 参考以来不推荐使用Node.js

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

56

@grandecomplex:您的解决方案有很多详细信息。如果这样写,将会更加清楚:

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

Object.prototype.toString.call对于您感兴趣的其他JavaScript类型很有用。您甚至可以检查null或undefined,这使其非常强大。
詹森·福利亚

49

var foo = function(){};
if (typeof foo === "function") {
  alert("is function")
}


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

35

尝试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

19

具有更多浏览器支持并且还包括异步功能的功能可能是:

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


9

对于那些对功能样式感兴趣或希望在元编程中使用更具表现力的方法(例如类型检查)的人来说,Ramda库可以完成此类任务可能会很有趣。

接下来的代码仅包含纯函数和无点函数:

const R = require('ramda');

const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);

const equalsSyncFunction = isPrototypeEquals(() => {});

const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);

从ES2017开始,async功能可用,因此我们也可以对其进行检查:

const equalsAsyncFunction = isPrototypeEquals(async () => {});

const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);

然后将它们组合在一起:

const isFunction = R.either(isSyncFunction, isAsyncFunction);

当然,应保护函数免受null和侵害undefined,以使其“安全”:

const safeIsFunction = R.unless(R.isNil, isFunction);

并且,完整的代码段总结如下:

const R = require('ramda');

const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);

const equalsSyncFunction = isPrototypeEquals(() => {});
const equalsAsyncFunction = isPrototypeEquals(async () => {});

const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);

const isFunction = R.either(isSyncFunction, isAsyncFunction);

const safeIsFunction = R.unless(R.isNil, isFunction);

// ---

console.log(safeIsFunction( function () {} ));
console.log(safeIsFunction( () => {} ));
console.log(safeIsFunction( (async () => {}) ));
console.log(safeIsFunction( new class {} ));
console.log(safeIsFunction( {} ));
console.log(safeIsFunction( [] ));
console.log(safeIsFunction( 'a' ));
console.log(safeIsFunction( 1 ));
console.log(safeIsFunction( null ));
console.log(safeIsFunction( undefined ));

但是,请注意,由于广泛使用了高阶函数,因此该解决方案的性能可能比其他可用选项低。


7

如果你使用Lodash你可以做到这一点_.isFunction

_.isFunction(function(){});
// => true

_.isFunction(/abc/);
// => false

_.isFunction(true);
// => false

_.isFunction(null);
// => false

true如果value是一个函数,则返回此方法,否则返回false


4

我发现,在IE8测试原生浏览器的功能时,使用toStringinstanceoftypeof没有工作。这是一种在IE8中效果很好的方法(据我所知):

function isFn(f){
    return !!(f && f.call && f.apply);
}
//Returns true in IE7/8
isFn(document.getElementById);

另外,您可以使用以下方法检查本机功能:

"getElementById" in document

虽然,我在某处读到这在IE7及以下版本中并不总是有效。


4

以下似乎也对我有用(从测试node.js):

var isFunction = function(o) {
     return Function.prototype.isPrototypeOf(o);
};

console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false

4

我认为您可以在Function原型上定义一个标志,并检查您要测试的实例是否继承了该标志

定义一个标志:

Function.prototype.isFunction = true; 

然后检查它是否存在

var foo = function(){};
foo.isFunction; // will return true

缺点是另一个原型可以定义相同的标志,因此毫无用处,但是如果您完全控制包含的模块,这是最简单的方法


如果foo未定义,它将失败并显示错误。更不用说您修改本机原型了,这是完全错误的。
卡米尔·奥尔泽肖夫斯基

3

从节点v0.11开始,您可以使用标准util函数:

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

2
util.isFunction已弃用
kehers


0

如先前的答案所示,解决方案是使用typeof。以下是NodeJ中的代码段,

    function startx() {
      console.log("startx function called.");
    }

 var fct= {};
 fct["/startx"] = startx;

if (typeof fct[/startx] === 'function') { //check if function then execute it
    fct[/startx]();
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.