Check if a variable is of function type
Suppose I have any variable, which is defined as follows:
var a = function() {/* Statements */};
I want a function which checks if the type of the variable is function-like. i.e. :
function foo(v) {if (v is function type?) {/* do something */}};
foo(a);
How can I check if the variable a
is of type Function
开发者_StackOverflowin the way defined above?
if (typeof v === 'function') {
// do something
}
Sure underscore's way is more efficient, but the best way to check, when efficiency isn't an issue, is written on underscore's page linked by @Paul Rosania.
Inspired by underscore, the final isFunction function is as follows:
function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
Note: This solution doesn't work for async functions, generators or proxied functions. Please see other answers for more up to date solutions.
There are several ways so I will summarize them all
- 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 theif
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
Underscore.js uses a more elaborate but highly performant test:
_.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
See: https://jsben.ch/B6h73
EDIT: updated tests suggest that typeof might be faster, see https://jsben.ch/B6h73
jQuery (deprecated since version 3.3) Reference
$.isFunction(functionName);
AngularJS Reference
angular.isFunction(value);
Lodash Reference
_.isFunction(value);
Underscore Reference
_.isFunction(object);
Node.js deprecated since v4.0.0 Reference
var util = require('util');
util.isFunction(object);
@grandecomplex: There's a fair amount of verbosity to your solution. It would be much clearer if written like this:
function isFunction(x) {
return Object.prototype.toString.call(x) == '[object Function]';
}
const foo = function() {};
if (typeof foo === 'function') {
console.log('is function')
}
Something with more browser support and also include async functions could be:
const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);
and then test it like:
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
Try the instanceof
operator: it seems that all functions inherit from the Function
class:
// 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
An other simply way:
var fn = function () {}
if (fn.constructor === Function) {
// true
} else {
// false
}
For those who's interested in functional style, or looks for more expressive approach to utilize in meta programming (such as type checking), it could be interesting to see Ramda library to accomplish such task.
Next code contains only pure and pointfree functions:
const R = require('ramda');
const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
const equalsSyncFunction = isPrototypeEquals(() => {});
const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
As of ES2017, async
functions are available, so we can check against them as well:
const equalsAsyncFunction = isPrototypeEquals(async () => {});
const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
And then combine them together:
const isFunction = R.either(isSyncFunction, isAsyncFunction);
Of course, function should be protected against null
and undefined
values, so to make it "safe":
const safeIsFunction = R.unless(R.isNil, isFunction);
And, complete snippet to sum up:
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 ));
However, note the this solution could show less performance than other available options due to extensive usage of higher-order functions.
If you use Lodash you can do it with _.isFunction.
_.isFunction(function(){});
// => true
_.isFunction(/abc/);
// => false
_.isFunction(true);
// => false
_.isFunction(null);
// => false
This method returns true
if value is a function, else false
.
The below seems to work for me as well (tested from node.js
):
var isFunction = function(o) {
return Function.prototype.isPrototypeOf(o);
};
console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false
I found that when testing native browser functions in IE8, using toString
, instanceof
, and typeof
did not work. Here is a method that works fine in IE8 (as far as I know):
function isFn(f){
return !!(f && f.call && f.apply);
}
//Returns true in IE7/8
isFn(document.getElementById);
Alternatively, you can check for native functions using:
"getElementById" in document
Though, I have read somewhere that this will not always work in IE7 and below.
I think you can just define a flag on the Function prototype and check if the instance you want to test inherited that
define a flag:
Function.prototype.isFunction = true;
and then check if it exist
var foo = function(){};
foo.isFunction; // will return true
The downside is that another prototype can define the same flag and then it's worthless, but if you have full control over the included modules it is the easiest way
This is an old question but there are some considerations in 2022:
First, browser compatibility: instanceof
is supported by all modern browsers as well as Deno and NodeJS.
Also, it's syntactically readable and more friendly than typeof
.
Finally, it provides a good performance over string comparison but is slower than typeof
. Therefore, for me this is the a good option
const fnc = () => {}
const isFunction = f => !!f && f instanceof Function
const isFunctionFaster = f => !!f && 'function' === typeof f
console.log({
isFunction: isFunction(fnc),
isFunctionFaster: isFunctionFaster(fnc),
})
Notice
It is important to understand that this is a optimized function for benchmarking. When you bench mark you want to pass all the test like null
, undefined
and some on possible parameters received. f && ...
filter this null
like parameters to reduce computation time.
- Caveats of
instanceof
operator:
This operator tests the presence of constructor.prototype
in the object's prototype chain. This usually (though not always) means object was constructed with constructor. Therefore, this process is slower compared with typeof
operator.
typeof v === 'function')
- Caveats of
typeof
operator:
This operator returns a string indicating the type of the operand's value. This is executed very fast.
- Caveats of
instanceof
andtypeof
operators:
Remember that a class declaration, it's also considered as a function by the these operators, as you can see in this snippet:
// 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}]`)
Here is a basic sample of the isFunction
and isFunctionFaster
usage with different instances:
// 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)}`)
}
Here is a basic benchmark of these functions:
/**
* 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]`)
Conclusion
In general isFunctionFaster
is faster than isFunction
in 30%.
you should use typeOf
operator in js.
var a=function(){
alert("fun a");
}
alert(typeof a);// alerts "function"
Since node v0.11 you can use the standard util function :
var util = require('util');
util.isFunction('foo');
if you are looking for a simple solution:
function isFunction(value) {
return value instanceof Function
}
Becareful about this :
typeof Object === "function" // true.
typeof Array === "function" // true
精彩评论