Compruebe si una variable es del tipo de función

904

Supongamos que tengo alguna variable, que se define de la siguiente manera:

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

Quiero una función que verifique si el tipo de la variable es similar a una función. es decir:

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

¿Cómo puedo verificar si la variable aes de tipo Functionen la forma definida anteriormente?

Jesufer Vn
fuente
2
aquí una referencia para esto la mayoría de las formas más comunes para comprobar esta jsben.ch/#/e5Ogr
EscapeNetscape

Respuestas:

380

Claro que la forma de subrayar es más eficiente, pero la mejor manera de verificar, cuando la eficiencia no es un problema, está escrita en la página de subrayado vinculada por @Paul Rosania.

Inspirada en el subrayado, la función final isFunction es la siguiente:

function isFunction(functionToCheck) {
 return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
Alex Grande
fuente
1
Puede haber alguien que haya realizado una investigación más extensa sobre el asunto, pero eche un vistazo a los resultados de la revisión 4 del jsperf con una simple "verificación de resultados" . isFunctionAmuestra una diferencia de implementación en comparación con los otros métodos.
Joel Purra
24
Con las pruebas de rendimiento actualizadas , parece que hay una gran diferencia de velocidad dependiendo de su navegador. En Chrome typeof(obj) === 'function'parece ser el más rápido con diferencia; Sin embargo, en Firefox obj instanceof Functiones el claro ganador.
Justin Warkentin
77
Con respecto a la parte: typeof solo debe usarse para verificar si las variables o propiedades no están definidas. En javascript.info/tutorial/type-detection en la sección Un buen uso de typeof y la siguiente, el autor afirma que el caso es exactamente lo contrario
Konrad Madej
11
Alex, tengo curiosidad por qué dices que typeof solo debe usarse para verificar si no está definido. Su nombre sugiere que su propósito es verificar el tipo de algo, no solo si existe. ¿Existen problemas técnicos o problemas que pueden surgir al usarlo para hacer una verificación de tipo, o es más una preferencia? Si hay advertencias, sería bueno enumerarlas para que otros puedan evitar tropezarse con ellas.
jinglesthula
14
solución excesivamente complicada
Daniel Garmoshka
1714
if (typeof v === "function") {
    // do something
}
selbie
fuente
44
Sólo ten cuidado con algunas cosas como typeof Object, typeof Datey typeof Stringque todos vuelven 'function'demasiado.
Dave Ward,
359
@Dave, no estoy seguro de cuál es el problema ya que esas son funciones.
Matthew Crumley
66
¿Cuál es la diferencia con if (v instanceOf Function)?
mquandalle
10
@mquandalle No hay gran diferencia, excepto instanceofque no funcionará si está verificando una función que proviene de otro documento (un iframe, tal vez). El rendimiento varía.
rvighne 01 de
8
a diferencia de la respuesta aceptada, esto también funciona para funciones asíncronas. Para un asyncfunctionToCheck, getType.toString.call(functionToCheck)==='[object AsyncFunction]'donde comotypeof asyncfunctionToCheck === 'function'
TDreama
132

Underscore.js utiliza una prueba más elaborada pero de alto rendimiento:

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

Ver: http://jsperf.com/alternative-isfunction-implementations

EDITAR: las pruebas actualizadas sugieren que typeof podría ser más rápido, consulte http://jsperf.com/alternative-isfunction-implementations/4

Paul Rosania
fuente
¿Hay alguna razón particular para usar este enfoque que typof?
sv_en
1
La versión de Underscore es mucho más rápida en la mayoría de los navegadores. Ver: jsperf.com/alternative-isfunction-implementations
Paul Rosania
13
Seguro que me gusta el guión bajo, simple pero poderoso. Dicho esto, probablemente valga la pena señalar que esta implementación podría ser suplantada por un objeto con esos atributos.
studgeek
3
@PaulRosania Hoy me topé con estas pruebas de rendimiento y las actualicé con verificación y más datos de prueba como revisión 4. Ejecútelo para aumentar la cobertura de prueba del navegador. Es más lento en operaciones por segundo (debido a las muchas pruebas), pero también muestra una diferencia de implementación (abra su consola de JavaScript y vuelva a cargar la página, puede haber mensajes de error registrados). Nota: La revisión 3 agregó isFunctionD (basado solo en typeof == "function"), y parece ser mucho más rápido que la versión "rápida" de Underscore.
Joel Purra
66
Esta respuesta es un poco engañosa ahora, ya que Underscore.js está ahora en la revisión 12 , no en la revisión 4 mencionada anteriormente, de su prueba de isFunction()implementaciones alternativas . Actualmente usa algo muy cercano a lo que sugirió dandean .
Jonathan Eunice
112

Hay varias formas, así que las resumiré todas

  1. La mejor manera es:
    function foo (v) {if (v instanceof Function) {/ * haz algo * /}};
    
    
    La solución más eficiente (sin comparación de cadenas) y elegante: la instancia del operador ha sido compatible con los navegadores durante mucho tiempo, así que no se preocupe, funcionará en IE 6.
  2. La siguiente mejor manera es:
    function foo (v) {if (typeof v === "function") {/ * haz algo * /}};
    
    
    La desventaja de esto typeofes que es susceptible a fallas silenciosas, mal, así que si tiene un error tipográfico (por ejemplo, "finction"), en este caso, el `if` simplemente devolverá falso y no sabrá que tiene un error hasta más tarde tu codigo
  3. La siguiente mejor manera es:
    function isFunction (functionToCheck) {
        var getType = {};
        return functionToCheck && getType.toString.call (functionToCheck) === '[Función de objeto]';
    }
    
    
    Esto no tiene ninguna ventaja sobre la solución n. ° 1 o n. ° 2, pero es mucho menos legible. Una versión mejorada de esto es
    function isFunction (x) {
        return Object.prototype.toString.call (x) == '[función de objeto]';
    }
    
    
    pero aún menos semántica que la solución n. ° 1
dalimian
fuente
10
La primera solución falla en caso de que una función pase a un contexto de marco diferente. Por ejemplo, de un iframe top.Function !== Function. Para estar seguro, use el segundo (con suerte, cualquier error ortográfico de la "función" se corregirá durante la depuración).
MaxArt
Con respecto a su punto sobre los errores tipográficos: cualquier código que tenga este error tipográfico puede fallar rápidamente / no es más evidente que cualquier otro error basado en errores tipográficos. typeof === "function" es la solución más limpia. Además, su "mejor" solución en la que utiliza instanceofno tiene en cuenta múltiples globales, como un cheque a través de cuadros, y puede devolver falsos negativos.
brainkim
84

jQuery (en desuso desde la versión 3.3) Referencia

$.isFunction(functionName);

AngularJS Referencia de

angular.isFunction(value);

Lodash Referencia de

_.isFunction(value);

Guion bajo Referencia de

_.isFunction(object); 

Node.js en desuso desde v4.0.0 Referencia

var util = require('util');
util.isFunction(object);
Cesar Loachamin
fuente
56

@grandecomplex: Hay una buena cantidad de verbosidad en su solución. Sería mucho más claro si se escribiera así:

function isFunction(x) {
  return Object.prototype.toString.call(x) == '[object Function]';
}
dandean
fuente
Object.prototype.toString.call es útil para otros tipos de javascript que le interesan. Incluso puede verificar si son nulos o indefinidos, lo que lo hace muy poderoso.
Jason Foglia
49

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

wsc
fuente
1
... y (() => (typeof obj === 'function') && doSomething())sigue siendo la opción más rápida.
Darcher
35

Pruebe el instanceofoperador: parece que todas las funciones heredan de la Functionclase:

// 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
Alexander Abakumov
fuente
19

Algo con más compatibilidad con el navegador y también incluye funciones asíncronas podría ser:

const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);

y luego probarlo como:

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
Alireza
fuente
11

Otra forma sencilla:

var fn = function () {}
if (fn.constructor === Function) {
  // true
} else {
  // false
}
GuillaumeL
fuente
1
si fn no estará definido, arrojará un error
Kamil Orzechowski
fn && fn.constructor === Function¿Qué tal esto?
Yaroslav Melnichuk
9

Para aquellos que están interesados ​​en el estilo funcional, o buscan un enfoque más expresivo para utilizar en la meta programación (como la verificación de tipos), podría ser interesante ver a Ramda biblioteca para realizar dicha tarea.

El siguiente código contiene solo funciones puras y sin puntos:

const R = require('ramda');

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

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

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

A partir de ES2017, las asyncfunciones están disponibles, por lo que también podemos verificarlas:

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

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

Y luego combinarlos juntos:

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

Por supuesto, la función debe protegerse contra nully los undefinedvalores, para que sea "segura":

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

Y, fragmento completo para resumir:

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 ));

Sin embargo, tenga en cuenta que esta solución podría mostrar menos rendimiento que otras opciones disponibles debido al uso extensivo de funciones de orden superior.

Orgánico dañado
fuente
7

Si usa Lodash, puede hacerlo con _.isFunction .

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

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

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

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

Este método devuelve truesi el valor es una función, de lo contrario false.

slorenzo
fuente
4

He descubierto que al probar las funciones del navegador nativo en IE8, usando toString, instanceofy typeofno funcionó. Aquí hay un método que funciona bien en IE8 (que yo sepa):

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

Alternativamente, puede verificar las funciones nativas usando:

"getElementById" in document

Sin embargo, he leído en alguna parte que esto no siempre funcionará en IE7 y versiones inferiores.

Azmisov
fuente
4

Lo siguiente parece funcionar para mí también (probado desde node.js):

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

console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false
Marcus Junius Brutus
fuente
4

Creo que puede definir un indicador en el prototipo de Función y verificar si la instancia que desea probar heredó eso

definir una bandera:

Function.prototype.isFunction = true; 

y luego verifica si existe

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

La desventaja es que otro prototipo puede definir la misma bandera y luego no vale nada, pero si tiene control total sobre los módulos incluidos, es la forma más fácil

Danny Mor
fuente
Fallará con Error si foo no está definido. Sin mencionar que modifica el prototipo nativo, lo cual es totalmente incorrecto.
Kamil Orzechowski
3

Desde el nodo v0.11 puede usar la función de utilidad estándar:

var util = require('util');
util.isFunction('foo');
moklick
fuente
2
util.isFunction está en desuso
kehers
2

deberías usar typeOfoperator en js.

var a=function(){
    alert("fun a");
}
alert(typeof a);// alerts "function"
Rajesh Paul
fuente
0

La solución, como han mostrado algunas respuestas anteriores, es usar typeof. el siguiente es un fragmento de código en NodeJs,

    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]();
  }
Badr Bellaj
fuente