Jes*_* Vn 826 javascript
假设我有任何变量,定义如下:
var a = function() {/* Statements */};
Run Code Online (Sandbox Code Playgroud)
我想要一个函数来检查变量的类型是否像函数一样.即:
function foo(v) {if (v is function type?) {/* do something */}};
foo(a);
Run Code Online (Sandbox Code Playgroud)
如何以上面定义的方式检查变量a
是否类型Function
?
sel*_*bie 1600
if (typeof v === "function") {
// do something
}
Run Code Online (Sandbox Code Playgroud)
Ale*_*nde 347
当然,下划线的方式更有效,但是当效率不是问题时,检查的最佳方式是在由@Paul Rosania链接的下划线页面上.
灵感来自下划线,最终的isFunction功能如下:
function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
Run Code Online (Sandbox Code Playgroud)
Pau*_*nia 129
Underscore.js使用更精细但高性能的测试:
_.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
Run Code Online (Sandbox Code Playgroud)
请参阅:http://jsperf.com/alternative-isfunction-implementations
编辑:更新的测试表明typeof可能更快,请参阅http://jsperf.com/alternative-isfunction-implementations/4
小智 103
有几种方法可以总结它们
function foo(v) {if (v instanceof Function) {/* do something */} };最常见的(没有字符串比较)和优雅的解决方案 - 在浏览器中支持instanceof运算符很长一段时间,所以不要担心 - 它将在IE 6中运行.
function foo(v) {if (typeof v === "function") {/* do something */} };缺点
typeof
是它容易出现静音失败,不好,所以如果你有一个拼写错误(例如"finction") - 在这种情况下,`if`将只返回false,你不会知道你有错误,直到后来你的代码
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少得多的语义
Ces*_*min 81
jQuery(自3.3版以来已弃用)参考
$.isFunction(functionName);
Run Code Online (Sandbox Code Playgroud)
AngularJS 参考
angular.isFunction(value);
Run Code Online (Sandbox Code Playgroud)
Lodash 参考
_.isFunction(value);
Run Code Online (Sandbox Code Playgroud)
下划线 参考
_.isFunction(object);
Run Code Online (Sandbox Code Playgroud)
自v4.0.0 引用以来,不推荐使用Node.js
var util = require('util');
util.isFunction(object);
Run Code Online (Sandbox Code Playgroud)
dan*_*ean 54
@grandecomplex:你的解决方案有相当多的冗长.如果这样写的话会更清楚:
function isFunction(x) {
return Object.prototype.toString.call(x) == '[object Function]';
}
Run Code Online (Sandbox Code Playgroud)
小智 47
var foo = function(){};
if (typeof foo === "function") {
alert("is function")
}
Run Code Online (Sandbox Code Playgroud)
小智 31
尝试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
Run Code Online (Sandbox Code Playgroud)
小智 11
另一个简单的方法:
var fn = function () {}
if (fn.constructor === Function) {
// true
} else {
// false
}
Run Code Online (Sandbox Code Playgroud)
Ali*_*eza 11
具有更多浏览器支持并且还包括异步功能的功能可能是:
const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);
Run Code Online (Sandbox Code Playgroud)
然后像这样测试它:
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
Run Code Online (Sandbox Code Playgroud)
对于那些对函数风格感兴趣的人,或者在元编程中寻找更具表现力的方法(例如类型检查),看看Ramda库来完成这样的任务会很有趣.
下一个代码只包含pure和pointfree函数:
const R = require('ramda');
const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
const equalsSyncFunction = isPrototypeEquals(() => {});
const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
Run Code Online (Sandbox Code Playgroud)
从ES2017开始,async
功能可用,因此我们也可以检查它们:
const equalsAsyncFunction = isPrototypeEquals(async () => {});
const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
Run Code Online (Sandbox Code Playgroud)
然后将它们组合在一起:
const isFunction = R.either(isSyncFunction, isAsyncFunction);
Run Code Online (Sandbox Code Playgroud)
当然,应该保护功能null
和undefined
价值,以使其"安全":
const safeIsFunction = R.unless(R.isNil, isFunction);
Run Code Online (Sandbox Code Playgroud)
并且,完整的摘要总结:
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 ));
Run Code Online (Sandbox Code Playgroud)
但请注意,由于大量使用高阶函数,此解决方案可能会显示出比其他可用选项更低的性能.
这是一个老问题,但 2022 年有一些考虑:
首先,浏览器兼容性:instanceof
所有现代浏览器以及 Deno 和 NodeJS 都支持。此外,它在语法上比typeof
. 最后,它比字符串比较提供了良好的性能,但比typeof
. 因此,对我来说这是一个不错的选择
const fnc = () => {}
const isFunction = f => !!f && f instanceof Function
const isFunctionFaster = f => !!f && 'function' === typeof f
console.log({
isFunction: isFunction(fnc),
isFunctionFaster: isFunctionFaster(fnc),
})
Run Code Online (Sandbox Code Playgroud)
重要的是要了解这是针对基准测试的优化函数。当您进行基准测试时,您希望通过所有测试,例如null
,undefined
以及一些关于收到的可能参数的测试。f && ...
过滤null
类似参数以减少计算时间。
instanceof
运营商注意事项:constructor.prototype
该运算符测试对象原型链中是否存在。这通常(尽管并非总是)意味着对象是用构造函数构造的。因此,这个过程比typeof
操作员要慢。
typeof v === '函数')
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}]`)
Run Code Online (Sandbox Code Playgroud)
以下是不同实例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)}`)
}
Run Code Online (Sandbox Code Playgroud)
以下是这些功能的基本基准:
/**
* 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]`)
Run Code Online (Sandbox Code Playgroud)
一般来说isFunctionFaster
快于isFunction
30%。
如果你使用Lodash,你可以使用_.isFunction.
_.isFunction(function(){});
// => true
_.isFunction(/abc/);
// => false
_.isFunction(true);
// => false
_.isFunction(null);
// => false
Run Code Online (Sandbox Code Playgroud)
true
如果value是函数,则此方法返回,否则false
.
下面的内容似乎也适合我(经过测试node.js
):
var isFunction = function(o) {
return Function.prototype.isPrototypeOf(o);
};
console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false
Run Code Online (Sandbox Code Playgroud)