假设有任意变量,定义如下:
var a = function() {/* Statements */};
我想要一个函数来检查变量的类型是否为类函数。例如:
function foo(v) {if (v is function type?) {/* do something */}};
foo(a);
我怎样才能检查变量a是否为上述定义的函数类型?
假设有任意变量,定义如下:
var a = function() {/* Statements */};
我想要一个函数来检查变量的类型是否为类函数。例如:
function foo(v) {if (v is function type?) {/* do something */}};
foo(a);
我怎样才能检查变量a是否为上述定义的函数类型?
js使用了一个更精细但高性能的测试:
_.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
参见:https://jsben.ch/B6h73
编辑:更新的测试表明typeof可能更快,参见https://jsben.ch/B6h73
当然,下划线的方式更有效率,但当效率不是问题时,最好的检查方法是在@Paul Rosania的下划线页面上写的。
受下划线的启发,最后的isFunction函数如下:
function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
注意:此解决方案不适用于异步函数、生成器或代理函数。请参阅其他答案,以了解更多最新的解决方案。
@grandecomplex:你的解决方案相当冗长。如果这样写会更清楚:
function isFunction(x) {
return Object.prototype.toString.call(x) == '[object Function]';
}
尝试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
我发现在测试IE8中的本地浏览器功能时,使用toString、instanceof和typeof都不能工作。下面是一个在IE8中运行良好的方法(据我所知):
function isFn(f){
return !!(f && f.call && f.apply);
}
//Returns true in IE7/8
isFn(document.getElementById);
或者,您可以使用以下方法检查本机函数:
"getElementById" in document
不过,我在某个地方读到过,这在IE7及以下版本并不总是有效。
有几种方法,所以我将把它们都总结一下
Best way is: function foo(v) {if (v instanceof Function) {/* do something */} }; Most performant (no string comparison) and elegant solution - the instanceof operator has been supported in browsers for a very long time, so don't worry - it will work in IE 6. Next best way is: function foo(v) {if (typeof v === "function") {/* do something */} }; disadvantage of typeof is that it is susceptible to silent failure, bad, so if you have a typo (e.g. "finction") - in this case the if will just return false and you won't know you have an error until later in your code The next best way is: function isFunction(functionToCheck) { var getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; } This has no advantage over solution #1 or #2 but is a lot less readable. An improved version of this is function isFunction(x) { return Object.prototype.toString.call(x) == '[object Function]'; } but still lot less semantic than solution #1
你应该在js中使用typeOf操作符。
var a=function(){
alert("fun a");
}
alert(typeof a);// alerts "function"
jQuery(3.3版已弃用)参考
$.isFunction(functionName);
AngularJS参考
angular.isFunction(value);
Lodash参考
_.isFunction(value);
强调参考
_.isFunction(object);
Node.js自v4.0.0参考版起已弃用
var util = require('util');
util.isFunction(object);
另一种简单的方法:
var fn = function () {}
if (fn.constructor === Function) {
// true
} else {
// false
}
下面的代码似乎也适用于我(从node.js测试):
var isFunction = function(o) {
return Function.prototype.isPrototypeOf(o);
};
console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false
我认为你可以在Function原型上定义一个标志,然后检查你想测试的实例是否继承了这个标志
定义一个标志:
Function.prototype.isFunction = true;
然后检查它是否存在
var foo = function(){};
foo.isFunction; // will return true
缺点是,另一个原型可以定义相同的标志,然后它是没有价值的,但如果你可以完全控制所包含的模块,这是最简单的方法
如果你使用Lodash,你可以用_.isFunction来实现。
_.isFunction(function(){});
// => true
_.isFunction(/abc/);
// => false
_.isFunction(true);
// => false
_.isFunction(null);
// => false
如果value是一个函数,该方法返回true,否则返回false。
对于那些对函数式风格感兴趣,或者在元编程中寻找更有表现力的方法(如类型检查)的人来说,看到Ramda库来完成这样的任务可能会很有趣。
下面的代码只包含纯函数和无点函数:
const R = require('ramda');
const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
const equalsSyncFunction = isPrototypeEquals(() => {});
const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
从ES2017开始,异步函数是可用的,所以我们也可以检查它们:
const equalsAsyncFunction = isPrototypeEquals(async () => {});
const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
然后把它们组合在一起:
const isFunction = R.either(isSyncFunction, isAsyncFunction);
当然,函数应该被保护不受空值和未定义值的影响,所以为了使它“安全”:
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 ));
但是,请注意,由于大量使用高阶函数,此解决方案的性能可能低于其他可用选项。
有更多的浏览器支持,也包括异步函数可以是:
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
注意这一点:
typeof Object === "function" // true.
typeof Array === "function" // true
如果你正在寻找一个简单的解决方案:
function isFunction(value) {
return value instanceof Function
}
这是一个老问题,但在2022年有一些考虑:
首先,浏览器兼容性:所有现代浏览器以及Deno和NodeJS都支持instanceof。 此外,它在语法上可读,比typeof更友好。 最后,它提供了比字符串比较更好的性能,但比typeof慢。因此,对我来说,这是一个很好的选择
Const FNC = () => {} const isFunction = f => !f && f instanceof函数 const isFunctionFaster = f => !!F && 'function' ===类型的F console.log ({ isFunction: isFunction (fnc), isFunctionFaster: isFunctionFaster (fnc), })
请注意
重要的是要理解这是一个用于基准测试的优化函数。当你做基准测试时,你想要通过所有的测试,比如null, undefined和一些接收到的可能参数。F &&…过滤此null类参数以减少计算时间。
instanceof操作符的注意事项:
此操作符测试构造函数是否存在。对象的原型链中的原型。这通常(虽然不总是)意味着对象是用构造函数构造的。因此,这个过程比typeof操作符慢。
Typeof v === 'function')
typeof操作符的注意事项:
该操作符返回指示操作数值类型的字符串。执行速度非常快。
instanceof和typeof操作符的注意事项:
记住,一个类声明,它也被这些操作符视为一个函数,正如你在这段代码中看到的:
// Class Declaration class A {} // Instances const obj = {} const arr = [] const fnc = () => {} const a = new A() console.log('typeof') console.log(`Object[${typeof Object}], obj[${typeof obj}]`) console.log(`Array[${typeof Array}], arr[${typeof arr}]`) console.log(`Function[${typeof Function}], fnc[${typeof fnc}]`) console.log(`A[${typeof A}], a[${typeof a}]`) console.log('instanceof') console.log(`Object[${Object instanceof Object}], obj[${obj instanceof Object}]`) console.log(`Array[${Array instanceof Array}], arr[${arr instanceof Array}]`) console.log(`Function[${Function instanceof Function}], fnc[${fnc instanceof Function}]`) console.log(`A[${A instanceof A}], a[${a instanceof A}]`)
下面是isFunction和isFunctionFaster在不同实例中的基本示例:
// Functions const isNil = o => o == null const isFunction = f => !!f && f instanceof Function const isFunctionFaster = f => !!f && 'function' === typeof f class A {} function basicFnc(){} async function asyncFnc(){} const arrowFnc = ()=> {} const arrowRFnc = ()=> 1 // Not functions const obj = {} const arr = [] const str = 'function' const bol = true const num = 1 const a = new A() const list = [ isFunction, isFunctionFaster, basicFnc, arrowFnc, arrowRFnc, asyncFnc, Array, Date, Object, Number, String, Symbol, A, obj, arr, str, bol, num, a, null, undefined, ] for (const arg of list) { console.log(`${arg} is a function: ${isFunction(arg)}`) }
下面是这些函数的基本基准:
/** * Figure out how long it takes for a method to execute. * * @param {Function} method to test * @param {number} iterations number of executions. * @param {Array} args to pass in. * @param {T} context the context to call the method in. * @return {number} the time it took, in milliseconds to execute. */ const bench = (method, list, iterations, context) => { let start = 0 const timer = action => { const time = performance.now() switch (action) { case 'start': start = time return 0 case 'stop': const elapsed = time - start start = 0 return elapsed default: return time - start } }; const result = [] timer('start') list = [...list] for (let i = 0; i < iterations; i++) { for (const args of list) { result.push(method.apply(context, args)) } } const elapsed = timer('stop') console.log(`Called method [${method.name}]`) console.log(`Mean: ${elapsed / iterations}`) console.log(`Exec. time: ${elapsed}`) return elapsed } const fnc = () => {} const isFunction = (f) => f && f instanceof Function const isFunctionFaster = (f) => f && 'function' === typeof f class A {} function basicFnc(){} async function asyncFnc(){} const arrowFnc = ()=> {} const arrowRFnc = ()=> 1 // Not functions const obj = {} const arr = [] const str = 'function' const bol = true const num = 1 const a = new A() const list = [ [isFunction], [basicFnc], [arrowFnc], [arrowRFnc], [asyncFnc], [Array], [Date], [Object], [Number], [String], [Symbol], [A], [obj], [arr], [str], [bol], [num], [a], [null], [undefined], ] const e1 = bench(isFunction, list, 10000) const e2 = bench(isFunctionFaster, list, 10000) const rate = e2/e1 const percent = Math.abs(1 - rate)*100 console.log(`[isFunctionFaster] is ${(percent).toFixed(2)}% ${rate < 1 ? 'faster' : 'slower'} than [isFunction]`)
结论
一般来说,isFunctionFaster比isFunction快30%。