Cómo saber si una función de JavaScript está definida

302

¿Cómo saber si se define una función en JavaScript?

Quiero hacer algo como esto

function something_cool(text, callback) {
    alert(text);
    if( callback != null ) callback();
}

Pero me da un

la devolución de llamada no es una función

error cuando la devolución de llamada no está definida.

Aaron Lee
fuente

Respuestas:

475
typeof callback === "function"
Tom Ritter
fuente
47
Esto no es realmente una cadena mágica, ya que el conjunto de valores typeof se define con precisión en la especificación ECMA. Aunque la sintaxis para esto es un poco tonta para empezar, es un Javascript idiomático perfectamente razonable.
Ben Zotto
2
@quixoto: entendido, supongo que lo que quiero decir es que aún necesita tener una cadena de todos modos, prefiero no tener más cadenas literales que ensucian mi código de las absolutamente necesarias; por lo tanto, este no es mi ideal para probar si algo es una función.
Jason Bunting
44
Y sí, "magia" era una elección de palabras descuidada y pobre: ​​quise decir "cadena literal", no "cadena mágica". Culpa mía. :)
Jason Bunting
1
JSPerf - jsperf.com/…
Chris GW Green
Asegúrese de eliminar el paréntesis en su función y solo use el nombre de la función en la condición if o la función se invocará en lugar de darle verdadero o falso.
Russell Strauss
236

Todas las respuestas actuales usan una cadena literal, que prefiero no tener en mi código si es posible; esto no (y proporciona un significado semántico valioso, para arrancar):

function isFunction(possibleFunction) {
  return typeof(possibleFunction) === typeof(Function);
}

Personalmente, trato de reducir la cantidad de cadenas que cuelgan en mi código ...


Además, aunque soy consciente de que typeofes un operador y no una función, hay poco daño en el uso de la sintaxis que lo hace aparecer como este último.

Jason Bunting
fuente
77
¿Cómo se supone que debo usar esta función? He intentado isFunction(not_defined))donde not_definedes el nombre de la función que no está definida y FireBug regresar not_defined is not definedlo cual es correcto, pero su función debe devolver falso y no generan errores ...
Wookie88
@ Wookie88: Técnicamente hablando, la función ilustrada en mi respuesta no devuelve tanto un error como un error porque el intérprete de JavaScript está tratando de resolver el símbolo not_definedpara pasarle su valor isFunction()y no lo resuelve. No se puede hacer nada para definir isFunction()este problema.
Jason Bunting
3
@ZacharyYates La forma de evitar el ReferenceError significaría evitar trabajar con una referencia a la función quizás no definida. Puede hacer la verificación de tipo dentro de la llamada a la función y pasar el resultado a la función. jsfiddle.net/qNaxJ Tal vez no sea tan agradable, pero al menos, no se utilizan condiciones;)
netiul
8
O evite una función isFunctiony haga lo justo (typeof no_function == typeof Function).
netiul
2
@JasonBunting Si vas a ser tan exigente, realmente deberías usarlo typeof(Function())porque Function es una función; pero también lo son Array, Object y otros prototipos incorporados (por falta de un término mejor). Si estuviera buscando una matriz que no usaría, typeof(array) === typeof(Array)por ejemplo; usaría typeof(array) === typeof(Array())porque realmente necesita evaluar la función si está siendo cuidadoso y consistente.
seanmhanson
16
if (callback && typeof(callback) == "function")

Tenga en cuenta que de devolución de llamada (por sí mismo) se evalúa como falsesi se trata de undefined, null, 0, o false. En comparación con nulles demasiado específico.

Robin como el pájaro
fuente
2
También tenga en cuenta que si callbackse evalúa a sí mismo como un valor "falso-y", entonces su tipo nunca puede ser "función".
Joe
55
@ Joe, pero debido a un cortocircuito, esa prueba no se realizará si la devolución de llamada se evalúa como falsa.
Fabio A.
3
Esta solución no funciona, porque la primera condición activará una excepción de inmediato. esto puede funcionar, para una propiedad de un objeto: if (obj.callback) {...}
Roey
8

Esos métodos para saber si se implementa una función también fallan si la variable no está definida, por lo que estamos usando algo más poderoso que admite recibir una cadena:

function isFunctionDefined(functionName) {
    if(eval("typeof(" + functionName + ") == typeof(Function)")) {
        return true;
    }
}

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}
patriciorocca
fuente
Creo que es una buena respuesta, tienes razón, todos los métodos anteriores fallan es que la función no está definida.
Matteo Conta
Es trivial evitar referencias indefinidas, simplemente consulte en typeof window.doesthisexistlugar de doesthisexist. Sin embargo, el uso de eval (que: es malo) como se muestra solo funcionará con funciones con nombre; esto no funcionaría con el caso de uso en la pregunta.
AD7six
Tenga en cuenta que esto solo funciona con un alcance global, mientras que la respuesta aceptada también funciona con funciones de alcance local.
inf3rno
6

Nuevo en JavaScript No estoy seguro de si el comportamiento ha cambiado, pero la solución dada por Jason Bunting (hace 6 años) no funcionará si es posible La función no está definida.

function isFunction(possibleFunction) {
  return (typeof(possibleFunction) == typeof(Function));
}

Esto arrojará un ReferenceError: possibleFunction is not definederror cuando el motor intente resolver el símbolo posible Función (como se menciona en los comentarios a la respuesta de Jason)

Para evitar este comportamiento, solo puede pasar el nombre de la función que desea verificar si existe. Entonces

var possibleFunction = possibleFunction || {};
if (!isFunction(possibleFunction)) return false;

Esto establece que una variable sea la función que desea verificar o el objeto vacío si no está definido y, por lo tanto, evita los problemas mencionados anteriormente.

NectarSoft
fuente
Para ser completamente claro: mi código no arroja el error, ese es solo el analizador JavaScript que hace eso. Lo mismo sucedería si intentara usar un identificador indefinido de esa manera.
Jason Bunting
6

Tratar:

if (typeof(callback) == 'function')
bdukes
fuente
Hola, no use la comparación "suelta" (==) siempre use '===' para comparar incluso el tipo de la variable.
Joel Carneiro
4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}
ConroyP
fuente
4
if ('function' === typeof callback) ...
Andrew Hedges
fuente
3
Un poco pedante, y todavía usa un literal de cadena. ¿Qué tal if(typeof Function === typeof callback)...? :)
Jason Bunting
@JasonBunting Curioso, ¿qué tiene de malo usar el literal de cadena?
Bsienn
@Bsienn: como dije, es pedante de mi parte, pero aquí está la cosa. Digamos que usa el código con el literal de cadena, y la llamada a typeofdevuelve algo diferente más tarde (tal vez "Función" en lugar de "función"), debido a una implementación nueva / diferente de JavaScript; parece que sería menos probable que una implementación nueva / diferente rompería la typeof Function === typeof callbackverificación porque debería ser la misma a nivel semántico.
Jason Bunting
4
typeof(callback) == "function"
dashtinejad
fuente
4

yo podría hacer

try{
    callback();
}catch(e){};

Sé que hay una respuesta aceptada, pero nadie sugirió esto. No estoy seguro de si esto se ajusta a la descripción de idiomático, pero funciona para todos los casos.

En los motores JavaScript más nuevos, finallyse puede utilizar a.

Quentin Engles
fuente
Este es un atajo ordenado! Aunque no funcionará para probar únicamente si una función existe o está definida (sin también ejecutarla).
Beejor
Es verdad. Supuse una situación en la que la devolución de llamada es opcional en ese punto de ejecución. Usualmente uso de typeof callbacktodos modos.
Quentin Engles
Eso tiene sentido; Me estaba centrando en el título de la pregunta más que en su contenido. A veces me gusta la simplicidad de usar try-catch en toneladas de pruebas para algo. ¿Crees que hay una desventaja técnica al usarlo, en este caso frente a algo como typeof? ¿O se trata principalmente de hacer las cosas de una manera más adecuada / esperada?
Beejor
1
Si desea probar varios tipos, las excepciones no son tan buenas. Por ejemplo, el proyecto en el que estoy trabajando ahora utiliza una gran cantidad de verificación de tipos en una variable para ver si es una función, una cadena o lo que sea. En este proyecto realmente necesito los tipos. Para esto utilizo una variedad de tipos y verifico accepted_types.indexOf(typeof value) !== -1si está en una variedad de tipos. En esta situación, las excepciones serían prohibitivas en mi opinión.
Quentin Engles
2

Prueba esto:

callback instanceof Function
eWolf
fuente
1
No funciona Todavía te dará el error. Debe probarlo usted mismo antes de publicarlo como respuesta.
vbullinger
@vbullinger Acabo de probar nuevamente en Chrome, Firefox y Safari, funciona en todas partes. ¿Con qué motor experimentaste problemas?
eWolf
Firefox ¿Probó el caso cuando no se definió la devolución de llamada?
vbullinger
Esto se debe a que hace referencia directa a una variable indefinida, que nunca funciona: pastebin.com/UQz2AmzH
eWolf
3
Funciona cuando se usa en un parámetro de función, que es lo que solicitó el autor. Supongo que ECMAScript distingue los casos de una variable inexistente y una variable existente con un valor indefinido. Sería interesante saber más sobre esto.
eWolf
2

Si nos fijamos en la fuente de la biblioteca @Venkat Sudheer Reddy Aedama mencionada, subrayado, puede ver esto:

_.isFunction = function(obj) {
  return typeof obj == 'function' || false;
};

Esta es solo mi SUGERENCIA, SUGERENCIA respuesta:>

VentyCZ
fuente
2

Tratar:

if (!(typeof(callback)=='undefined')) {...}
Brian
fuente
1

Estaba buscando cómo verificar si se definió una función jQuery y no la encontré fácilmente.

Quizás lo necesite;)

if(typeof jQuery.fn.datepicker !== "undefined")
miguelmpn
fuente
igual que lo type0f($.datepicker) !== undefiledcontrario seráobject
vladkras
0

Si callback()está llamando no solo por una vez en una función, puede inicializar el argumento para su reutilización:

callback = (typeof callback === "function") ? callback : function(){};

Por ejemplo:

function something_cool(text, callback) {
    // Initialize arguments
    callback = (typeof callback === "function") ? callback : function(){};

    alert(text);

    if (text==='waitAnotherAJAX') {
        anotherAJAX(callback);
    } else {
        callback();
    }
}

La limitación es que siempre ejecutará el argumento de devolución de llamada aunque no esté definido.

Nick Tsai
fuente
0

Para funciones globales, puede usar esta en lugar de la evalsugerida en una de las respuestas.

var global = (function (){
    return this;
})();

if (typeof(global.f) != "function")
    global.f = function f1_shim (){
        // commonly used by polyfill libs
    };

Puedes usar global.f instanceof Functiontambién, pero afaik. el valor de Functionserá diferente en diferentes cuadros, por lo que solo funcionará correctamente con una aplicación de un solo cuadro. Es por eso que generalmente usamos typeofen su lugar. Tenga en cuenta que en algunos entornos también puede haber anomalías typeof f, por ejemplo, por MSIE 6-8, algunas de las funciones, por ejemplo, alerttenían el tipo "objeto".

Por funciones locales puede usar el de la respuesta aceptada. Puede probar si la función es local o global también.

if (typeof(f) == "function")
    if (global.f === f)
        console.log("f is a global function");
    else
        console.log("f is a local function");

Para responder a la pregunta, el código de ejemplo funciona para mí sin error en los últimos navegadores, por lo que no estoy seguro de cuál fue el problema:

function something_cool(text, callback) {
    alert(text);
    if( callback != null ) callback();
}

Nota: usaría en callback !== undefinedlugar de callback != null, pero hacen casi lo mismo.

inf3rno
fuente
0

La mayoría de las respuestas anteriores, si no todas, tienen efectos secundarios para invocar la función

aquí las mejores prácticas

tienes funcion

function myFunction() {
        var x=1;
    }
forma directa de probarlo

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
usando una cadena para que pueda tener un solo lugar para definir el nombre de la función

//byString
        var strFunctionName='myFunction'
        if( (typeof window[strFunctionName])=='function')
            alert(s+' is function');
        else
            alert(s+' is not defined');

TexWiller
fuente
0

Si desea redefinir funciones, es mejor utilizar variables de función, que se definen en su orden de aparición, ya que las funciones se definen globalmente, sin importar dónde ocurran.

Ejemplo de crear una nueva función que llama a una función anterior del mismo nombre:

A=function() {...} // first definition
...
if (typeof A==='function')
   oldA=A;
A=function() {...oldA()...} // new definition
David Spector
fuente
0

Esto funciono para mi

if( cb && typeof( eval( cb ) ) === "function" ){
    eval( cb + "()" );
}
Patrick Ogbuitepu
fuente
-2

Solución de una línea:

function something_cool(text, callback){
    callback && callback();
}
Samir Alajmovic
fuente
Su ejemplo muestra exactamente eso, que quiere que se llame a la función si está definida, y si no lo está, no sucede nada. jsfiddle.net/nh1cxxg6 Las funciones que devuelven valores falsos / falsos aún se llaman. Por supuesto, esto no funciona cuando desea que se devuelvan los valores.
Samir Alajmovic
Ah, leí mal su pregunta. Sin embargo, esto causaría una excepción si la devolución de llamada no es una función.
Frank Bryce