Comment savoir si une fonction JavaScript est définie

302

Comment savoir si une fonction en JavaScript est définie?

Je veux faire quelque chose comme ça

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

Mais ça me fait

le rappel n'est pas une fonction

erreur lorsque le rappel n'est pas défini.

Aaron Lee
la source

Réponses:

475
typeof callback === "function"
Tom Ritter
la source
47
Ce n'est pas vraiment une chaîne magique, car l'ensemble des valeurs de typeof est précisément défini dans la spécification ECMA. Bien que la syntaxe soit un peu maladroite pour commencer, c'est un Javascript idiomatique parfaitement raisonnable.
Ben Zotto
2
@quixoto - compris, je suppose que ce que je veux dire, c'est que vous devez toujours avoir une chaîne malgré tout - je préfère ne pas avoir plus de chaînes littérales qui jonchent mon code que ce qui est absolument nécessaire; par conséquent, ce n'est pas mon idéal pour tester si quelque chose est une fonction.
Jason Bunting
4
Et oui, «magie» était un choix de mots bâclé et médiocre - je voulais dire «chaîne littérale» et non «chaîne magique». Ma faute. :)
Jason Bunting
1
JSPerf - jsperf.com/…
Chris GW Green
Assurez-vous de supprimer les parenthèses sur votre fonction et utilisez uniquement le nom de la fonction dans la condition if ou la fonction sera invoquée au lieu de vous donner true ou false.
Russell Strauss
236

Toutes les réponses actuelles utilisent une chaîne littérale, que je préfère ne pas avoir dans mon code si possible - cela ne fonctionne pas (et fournit une signification sémantique précieuse, pour démarrer):

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

Personnellement, j'essaie de réduire le nombre de chaînes qui traînent dans mon code ...


De plus, bien que je sache qu'il typeofs'agit d'un opérateur et non d'une fonction, il y a peu de mal à utiliser la syntaxe qui la fait apparaître comme cette dernière.

Jason Bunting
la source
7
Comment suis-je censé utiliser cette fonction? J'ai essayé isFunction(not_defined))not_definedest le nom de la fonction qui n'est pas définie et FireBug est retourné not_defined is not definedce qui est correct mais votre fonction devrait retourner false et ne pas générer d'erreur ...
Wookie88
@ Wookie88: Techniquement parlant, la fonction illustrée dans ma réponse ne renvoie pas une erreur autant qu'une erreur se produit car l'interpréteur JavaScript essaie de résoudre le symbole not_definedafin de transmettre sa valeur à isFunction()et ne parvient pas à le résoudre. Rien ne peut être fait à la définition de isFunction()pour résoudre ce problème.
Jason Bunting
3
@ZacharyYates La façon de contourner ReferenceError signifierait éviter de travailler avec une référence à la fonction qui n'est peut-être pas définie. Vous pouvez effectuer la vérification de type à l'intérieur de l'appel de fonction et transmettre le résultat à la fonction. jsfiddle.net/qNaxJ Peut-être pas si gentil, mais au moins, aucune
chaîne
8
Ou évitez une fonction isFunctionet faites juste (typeof no_function == typeof Function).
netiul
2
@JasonBunting Si vous voulez être aussi pointilleux, vous devriez vraiment l'utiliser typeof(Function())parce que Function est une fonction; mais il en va de même pour Array, Object et d'autres prototypes intégrés (faute d'un meilleur terme). Si vous recherchiez un tableau, vous ne l'utiliseriez pas typeof(array) === typeof(Array)par exemple; vous utiliseriez typeof(array) === typeof(Array())parce que vous avez réellement besoin d'évaluer la fonction si vous êtes prudent et cohérent.
seanmhanson
16
if (callback && typeof(callback) == "function")

Notez que le rappel (par lui - même) Evalue à falsesi elle est undefined, null, 0, ou false. La comparaison avec nullest trop spécifique.

Robin comme l'oiseau
la source
2
Notez également que si callbacklui - même est évalué à une valeur "false-y", son typeof ne peut jamais être "function".
Joe
5
@Joe, mais en raison d'un court-circuit, ce test ne sera pas effectué si le rappel est faux.
Fabio A.
3
cette solution ne fonctionne pas, car la première condition déclenchera immédiatement une exception. cela peut fonctionner, pour une propriété d'un objet: if (obj.callback) {...}
Roey
8

Ces méthodes pour savoir si une fonction est implémentée échouent également si la variable n'est pas définie, nous utilisons donc quelque chose de plus puissant qui prend en charge la réception d'une chaîne:

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

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}
patriciorocca
la source
Je pense que c'est une bonne réponse, vous avez raison, toutes les méthodes ci-dessus échouent, la fonction n'est pas définie.
Matteo Conta
Il est trivial d'éviter les références non définies - référez-vous simplement à la typeof window.doesthisexistplace de doesthisexist. Cependant, utiliser eval (qui: est mauvais) comme indiqué ne fonctionnera qu'avec les fonctions nommées - cela ne fonctionnerait pas avec le cas d'utilisation de la question.
AD7six
N'oubliez pas que cela ne fonctionne qu'avec la portée globale, tandis que la réponse acceptée fonctionne également avec les fonctions de portée locale.
inf3rno
6

Nouveau sur JavaScript Je ne sais pas si le comportement a changé mais la solution proposée par Jason Bunting (il y a 6 ans) ne fonctionnera pas si possible. La fonction n'est pas définie.

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

Cela jettera un ReferenceError: possibleFunction is not defined erreur lorsque le moteur tentera de résoudre le symbole possibleFunction (comme mentionné dans les commentaires de la réponse de Jason)

Pour éviter ce comportement, vous ne pouvez transmettre que le nom de la fonction que vous souhaitez vérifier si elle existe. Alors

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

Cela définit une variable comme étant la fonction que vous souhaitez vérifier ou l'objet vide si elle n'est pas définie et évite ainsi les problèmes mentionnés ci-dessus.

NectarSoft
la source
Pour être complètement clair: mon code ne renvoie pas l'erreur, c'est juste l'analyseur JavaScript qui fait cela. La même chose se produirait si vous tentiez d'utiliser un identifiant non défini de cette manière.
Jason Bunting
6

Essayer:

if (typeof(callback) == 'function')
bdukes
la source
HI, n'utilisez pas de comparaison "lâche" (==) utilisez toujours '===' pour comparer même le type de la variable.
Joel Carneiro
4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}
ConroyP
la source
4
if ('function' === typeof callback) ...
Andrew Hedges
la source
3
Un peu pédant, et utilise toujours un littéral de chaîne. Et alors if(typeof Function === typeof callback)...? :)
Jason Bunting
@JasonBunting Curieux, qu'est-ce qui ne va pas avec l'utilisation de chaîne littérale?
Bsienn
@Bsienn - comme je l'ai dit, c'est pédant pour moi, mais voici le problème. Supposons que vous utilisez le code avec la chaîne littérale et que l'appel à typeofrenvoie quelque chose de différent plus tard (peut-être "Function" au lieu de "function"), en raison d'une implémentation nouvelle / différente de JavaScript - il semble qu'il serait moins probable que une implémentation nouvelle / différente briserait le typeof Function === typeof callbackcontrôle car elle devrait être la même au niveau sémantique.
Jason Bunting
4
typeof(callback) == "function"
dashtinejad
la source
4

Je pourrais faire

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

Je sais qu'il y a une réponse acceptée, mais personne ne l'a suggérée. Je ne sais pas vraiment si cela correspond à la description d'idiomatique, mais cela fonctionne dans tous les cas.

Dans les moteurs JavaScript plus récents, a finallypeut être utilisé à la place.

Quentin Engles
la source
Ceci est un raccourci soigné! Bien que cela ne fonctionnera pas uniquement pour tester si une fonction existe ou est définie (sans également l'exécuter).
Beejor
C'est vrai. J'ai supposé une situation où le rappel est facultatif à ce point d'exécution. J'utilise habituellement de typeof callbacktoute façon.
Quentin Engles
Ça a du sens; Je me concentrais davantage sur le titre de la question que sur son contenu. Parfois, j'aime la simplicité d'utiliser try-catch sur des tonnes de tests pour quelque chose. Pensez-vous qu'il y a un inconvénient technique à l'utiliser, dans ce cas par rapport à quelque chose comme typeof? Ou s'agit-il principalement de faire les choses de manière plus appropriée / attendue?
Beejor
1
Si vous souhaitez tester plusieurs types, les exceptions ne sont pas si bonnes. Par exemple, le projet sur lequel je travaille en ce moment utilise beaucoup de vérification de type sur une variable pour voir s'il s'agit d'une fonction, d'une chaîne ou autre. Dans ce projet, j'ai vraiment besoin des types. Pour cela, j'utilise un tableau de types et vérifie accepted_types.indexOf(typeof value) !== -1si c'est dans une gamme de types. Dans cette situation, les exceptions seraient à mon avis prohibitives.
Quentin Engles
2

Essaye ça:

callback instanceof Function
eWolf
la source
1
Ça ne marche pas. Il vous donnera toujours l'erreur. Vous devriez l'essayer vous-même avant de le poster comme réponse.
vbullinger
@vbullinger Je viens de tester à nouveau dans Chrome, Firefox et Safari - fonctionne partout. Avec quel moteur avez-vous rencontré des problèmes?
eWolf
Firefox. Avez-vous testé le cas lorsque le rappel n'a pas été défini?
vbullinger
C'est parce que vous faites directement référence à une variable non définie, qui ne fonctionne jamais: pastebin.com/UQz2AmzH
eWolf
3
Cela fonctionne lorsqu'il est utilisé sur un paramètre de fonction, ce que l'auteur a demandé - je suppose que ECMAScript distingue les cas d'une variable inexistante et d'une variable existante avec une valeur indéfinie. Il serait intéressant d'en savoir plus à ce sujet.
eWolf
2

Si vous regardez la source de la bibliothèque @Venkat Sudheer Reddy Aedama mentionnée, underscorejs, vous pouvez voir ceci:

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

Ceci est juste mon indice, réponse indice:>

VentyCZ
la source
2

Essayer:

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

Je cherchais comment vérifier si une fonction jQuery était définie et je ne l'ai pas trouvée facilement.

Peut-être en aurais-je besoin;)

if(typeof jQuery.fn.datepicker !== "undefined")
miguelmpn
la source
même chose type0f($.datepicker) !== undefiledsera le casobject
vladkras
0

Si callback()vous n'appelez pas juste une fois dans une fonction, vous pouvez initialiser l'argument à réutiliser:

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

Par exemple:

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

    alert(text);

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

La limitation est qu'il exécutera toujours l'argument de rappel même s'il n'est pas défini.

Nick Tsai
la source
0

Pour les fonctions globales, vous pouvez utiliser celle-ci au lieu de evalsuggérée dans l'une des réponses.

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

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

Vous pouvez également l'utiliser global.f instanceof Function, mais afaik. la valeur de Functionsera différente dans différents cadres, donc cela ne fonctionnera correctement qu'avec une seule application de cadre. C'est pourquoi nous utilisons habituellement à la typeofplace. Notez que dans certains environnements, il peut y avoir des anomalies avec typeof f, par exemple par MSIE 6-8 certaines des fonctions par exemplealert avaient le type "objet".

Par fonctions locales, vous pouvez utiliser celle de la réponse acceptée. Vous pouvez également tester si la fonction est locale ou globale.

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

Pour répondre à la question, l'exemple de code fonctionne pour moi sans erreur dans les derniers navigateurs, donc je ne sais pas quel était le problème:

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

Remarque: j'utiliserais callback !== undefinedau lieu de callback != null, mais ils font presque la même chose.

inf3rno
la source
0

La plupart des réponses précédentes, sinon toutes, ont des effets secondaires pour invoquer la fonction

ici meilleure pratique

tu as une fonction

function myFunction() {
        var x=1;
    }
moyen direct de le tester

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
en utilisant une chaîne de sorte que vous ne pouvez avoir qu'un seul endroit pour définir le nom de la fonction

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

TexWiller
la source
0

Si vous souhaitez redéfinir des fonctions, il est préférable d'utiliser des variables de fonction, qui sont définies dans leur ordre d'occurrence, car les fonctions sont définies globalement, peu importe où elles se produisent.

Exemple de création d'une nouvelle fonction qui appelle une fonction précédente du même nom:

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

Cela a fonctionné pour moi

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

Solution en une ligne:

function something_cool(text, callback){
    callback && callback();
}
Samir Alajmovic
la source
Son exemple montre juste cela, qu'il veut que la fonction soit appelée si elle est définie, et si ce n'est pas le cas, il ne se passe rien. jsfiddle.net/nh1cxxg6 Les fonctions qui renvoient des valeurs falsey / false sont toujours appelées. Bien sûr, cela ne fonctionne pas lorsque vous souhaitez renvoyer des valeurs.
Samir Alajmovic
Ah, j'ai mal lu sa question. Cependant, cela provoquerait une exception si le rappel n'est pas une fonction.
Frank Bryce