Check if a variable is of function type
假设我有任何变量,定义如下:
1 | var a = function() {/* Statements */}; |
我想要一个函数,它检查变量的类型是否像函数一样。即:
1 2 | function foo(v) {if (v is function type?) {/* do something */}}; foo(a); |
如何检查变量
1 2 3 | if (typeof v ==="function") { // do something } |
当然,下划线的方法更有效,但当效率不是问题时,最好的检查方法是写在由@paul rosania链接的下划线页面上。
受下划线启发,最终的is function函数如下:
1 2 3 | function isFunction(functionToCheck) { return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]'; } |
.js使用了一个更复杂但性能更高的测试:
1 2 3 | _.isFunction = function(obj) { return !!(obj && obj.constructor && obj.call && obj.apply); }; |
参见:http://jspef.com/alternative-isfunction-implements
编辑:更新的测试表明类型可能更快,请参阅http://jspef.com/alternative-isfunction-implements/4
有几种方法,我将对它们进行总结
1 | function foo(v) {if (v instanceof Function) {/* do something */} }; |
大多数性能(无字符串比较)和优雅的解决方案——InstanceOfOperator在浏览器中已经支持很长时间了,所以不用担心——它将在IE6中工作。
1 | function foo(v) {if (typeof v ==="function") {/* do something */} }; |
1 2 3 4 | function isFunction(functionToCheck) { var getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; } |
与解决方案1或2相比,这没有优势,但可读性要差得多。改进后的版本是
1 2 3 | function isFunction(x) { return Object.prototype.toString.call(x) == '[object Function]'; } |
但语义仍然比解决方案低很多1
jquery(自3.3版起已弃用)引用
1 | $.isFunction(functionName); |
AngularJS参考
1 | angular.isFunction(value); |
矿脉基准
1 | _.isFunction(value); |
下划线引用
1 | _.isFunction(object); |
自v4.0.0引用以来不推荐使用node.js
1 2 | var util = require('util'); util.isFunction(object); |
@大复杂:你的解决方案相当冗长。如果这样写的话会更清楚:
1 2 3 | function isFunction(x) { return Object.prototype.toString.call(x) == '[object Function]'; } |
1 2 3 4 | var foo = function(){}; if (typeof foo ==="function") { alert("is function") } |
尝试使用
1 2 3 4 5 6 7 8 9 10 | // 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 2 3 4 5 6 | var fn = function () {} if (fn.constructor === Function) { // true } else { // false } |
对于那些对函数风格感兴趣,或者希望在元编程中使用更具表现力的方法(比如类型检查)的人来说,看到Ramda库来完成这样的任务可能很有趣。
下一个代码只包含纯函数和无点函数:
1 2 3 4 5 6 7 | const R = require('ramda'); const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals); const equalsSyncFunction = isPrototypeEquals(() => {}); const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction); |
截至ES2017年,
1 2 3 | const equalsAsyncFunction = isPrototypeEquals(async () => {}); const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction); |
然后将它们组合在一起:
1 | const isFunction = R.either(isSyncFunction, isAsyncFunction); |
当然,应该保护功能不受
1 | const safeIsFunction = R.unless(R.isNil, isFunction); |
并且,完整的片段总结如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 )); |
但是,请注意,由于高阶函数的广泛使用,此解决方案的性能可能比其他可用选项低。
具有更多浏览器支持以及包括异步函数的功能可以是:
1 | const isFunction = value => value && (Object.prototype.toString.call(value) ==="[object Function]" ||"function" === typeof value || value instanceof Function); |
然后像这样测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
如果您使用lodash,您可以使用.isfunction来完成它。
1 2 3 4 5 6 7 8 9 10 11 | _.isFunction(function(){}); // => true _.isFunction(/abc/); // => false _.isFunction(true); // => false _.isFunction(null); // => false |
此方法返回
以下似乎对我也适用(从
1 2 3 4 5 6 | var isFunction = function(o) { return Function.prototype.isPrototypeOf(o); }; console.log(isFunction(function(){})); // true console.log(isFunction({})); // false |
我发现,在IE8中测试本机浏览器功能时,使用
1 2 3 4 5 | function isFn(f){ return !!(f && f.call && f.apply); } //Returns true in IE7/8 isFn(document.getElementById); |
或者,可以使用以下命令检查本机函数:
1 | "getElementById" in document |
不过,我在某个地方读到,在IE7及以下版本中,这并不总是有效。
由于节点v0.11,您可以使用标准的util函数:
1 2 | var util = require('util'); util.isFunction('foo'); |
我认为您可以在函数原型上定义一个标志,并检查您想要测试的实例是否继承了这个标志
定义标志:
1 | Function.prototype.isFunction = true; |
然后检查它是否存在
1 2 | var foo = function(){}; foo.isFunction; // will return true |
缺点是,另一个原型可以定义相同的标志,然后它就毫无价值了,但是如果您对所包含的模块拥有完全的控制权,那么这是最简单的方法
您应该在JS中使用
1 2 3 4 | var a=function(){ alert("fun a"); } alert(typeof a);// alerts"function" |
如前面的一些答案所示,解决方案是使用typeof。以下是nodejs中的代码片段,
1 2 3 4 5 6 7 8 9 10 | 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](); } |