Wie erkennt man, ob eine JavaScript-Funktion definiert ist?

302

Woran erkennt man, ob eine Funktion in JavaScript definiert ist?

Ich möchte so etwas tun

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

Aber es bringt mir ein

Rückruf ist keine Funktion

Fehler, wenn Rückruf nicht definiert ist.

Aaron Lee
quelle

Antworten:

475
typeof callback === "function"
Tom Ritter
quelle
47
Dies ist keine magische Zeichenfolge, da der Satz von Wertetypen in der ECMA-Spezifikation genau definiert ist. Obwohl die Syntax dafür anfangs etwas doof ist, ist es durchaus vernünftiges idiomatisches Javascript.
Ben Zotto
2
@quixoto - verstanden, ich denke, ich meine, dass Sie trotzdem eine Zeichenfolge benötigen - ich hätte lieber keine wörtlicheren Zeichenfolgen in meinem Code als unbedingt erforderlich. Daher ist dies nicht mein Ideal, um zu testen, ob etwas eine Funktion ist.
Jason Bunting
4
Und ja, "Magie" war eine schlampige, schlechte Wortwahl - ich meinte "wörtliche Zeichenfolge", nicht "magische Zeichenfolge". Mein Fehler. :)
Jason Bunting
1
JSPerf - jsperf.com/…
Chris GW Green
Stellen Sie sicher, dass Sie die Klammern in Ihrer Funktion entfernen und nur den Funktionsnamen in der if-Bedingung verwenden. Andernfalls wird die Funktion aufgerufen, anstatt Ihnen true oder false zu geben.
Russell Strauss
236

Alle aktuellen Antworten verwenden eine Literalzeichenfolge, die ich nach Möglichkeit lieber nicht in meinem Code habe - dies ist nicht der Fall (und bietet zum Booten eine wertvolle semantische Bedeutung):

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

Persönlich versuche ich, die Anzahl der Zeichenfolgen in meinem Code zu reduzieren ...


Auch wenn mir bewusst ist, dass typeofes sich um einen Operator und nicht um eine Funktion handelt, kann die Verwendung der Syntax, die sie als letztere erscheinen lässt, wenig schaden.

Jason Bunting
quelle
7
Wie soll ich diese Funktion nutzen? Ich habe versucht, isFunction(not_defined))wo not_definedist der Name der Funktion, der nicht definiert ist und FireBug zurückgegeben, not_defined is not definedwas korrekt ist, aber Ihre Funktion sollte false zurückgeben und keinen Fehler erzeugen ...
Wookie88
@ Wookie88: Technisch gesehen gibt die in meiner Antwort dargestellte Funktion weniger einen Fehler zurück, als dass ein Fehler auftritt, da der JavaScript-Interpreter versucht, das Symbol aufzulösen not_defined, um seinen Wert an zu übergeben, isFunction()und es nicht auflöst. Es kann nichts unternommen werden isFunction(), um dieses Problem zu lösen.
Jason Bunting
3
@ZacharyYates Die Art und Weise, wie Sie den ReferenceError umgehen, würde bedeuten, dass Sie nicht mit einem Verweis auf die möglicherweise nicht definierte Funktion arbeiten. Sie können den Typcheck innerhalb des Funktionsaufrufs durchführen und das Ergebnis an die Funktion übergeben. jsfiddle.net/qNaxJ Vielleicht nicht so schön, aber zumindest keine Zeichenfolgen verwendet;)
netiul
8
Oder vermeiden Sie eine Funktion isFunctionund tun Sie es einfach (typeof no_function == typeof Function).
Netiul
2
@JasonBunting Wenn Sie so wählerisch sein wollen, sollten Sie wirklich verwenden, typeof(Function())weil Funktion eine Funktion ist; Dies gilt auch für Array-, Objekt- und andere integrierte Prototypen (mangels eines besseren Begriffs). Wenn Sie nach einem Array suchen würden, würden Sie es beispielsweise nicht verwenden typeof(array) === typeof(Array). Sie würden verwenden, typeof(array) === typeof(Array())weil Sie die Funktion tatsächlich bewerten müssen, wenn Sie vorsichtig und konsistent sind.
Seanmhanson
16
if (callback && typeof(callback) == "function")

Beachten Sie, dass Rückruf (von selbst) auswertet , um , falsewenn es undefined, null, 0, oder false. Der Vergleich mit nullist zu spezifisch.

Robin mag den Vogel
quelle
2
Beachten Sie auch, dass der callbackTyp von "false-y" niemals "function" sein kann , wenn er selbst einen "false-y" -Wert ergibt.
Joe
5
@ Joe, aber aufgrund eines Kurzschlusses wird dieser Test nicht durchgeführt, wenn der Rückruf als falsch ausgewertet wird.
Fabio A.
3
Diese Lösung funktioniert nicht, da die erste Bedingung sofort eine Ausnahme auslöst. Dies kann für eine Eigenschaft eines Objekts funktionieren: if (obj.callback) {...}
Roey
8

Diese Methoden, um festzustellen, ob eine Funktion implementiert ist, schlagen auch fehl, wenn keine Variable definiert ist. Daher verwenden wir etwas Stärkeres, das das Empfangen einer Zeichenfolge unterstützt:

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

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}
patriciorocca
quelle
Ich denke, das ist eine gute Antwort. Sie haben Recht. Alle oben genannten Methoden schlagen fehl, wenn die Funktion nicht definiert ist.
Matteo Conta
Es ist trivial, undefinierte Referenzen zu vermeiden - beziehen Sie sich einfach auf typeof window.doesthisexiststatt doesthisexist. Die gezeigte Verwendung von eval (was: böse ist) funktioniert jedoch nur mit benannten Funktionen - dies würde mit dem Anwendungsfall in der Frage nicht funktionieren.
AD7six
Beachten Sie, dass dies nur mit globalem Bereich funktioniert, während die akzeptierte Antwort auch mit lokalen Bereichsfunktionen funktioniert.
inf3rno
6

Neu in JavaScript Ich bin nicht sicher, ob sich das Verhalten geändert hat, aber die von Jason Bunting (vor 6 Jahren) gegebene Lösung funktioniert nicht, wenn möglich. Die Funktion ist nicht definiert.

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

Dies wird einen ReferenceError: possibleFunction is not definedFehler auslösen, wenn die Engine versucht, das Symbol "mögliche Funktion" aufzulösen (wie in den Kommentaren zu Jasons Antwort erwähnt).

Um dieses Verhalten zu vermeiden, können Sie nur den Namen der Funktion übergeben, die Sie überprüfen möchten, ob sie vorhanden ist. Damit

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

Dadurch wird eine Variable entweder als die zu überprüfende Funktion oder als leeres Objekt festgelegt, wenn sie nicht definiert ist, und so werden die oben genannten Probleme vermieden.

NectarSoft
quelle
Um ganz klar zu sein: Mein Code löst den Fehler nicht aus, das ist nur der JavaScript-Parser, der das macht. Das gleiche würde passieren, wenn Sie versuchen würden, einen undefinierten Bezeichner auf diese Weise zu verwenden.
Jason Bunting
6

Versuchen:

if (typeof(callback) == 'function')
bdukes
quelle
HI, verwenden Sie nicht den "losen" Vergleich (==). Verwenden Sie immer '===', um auch den Typ der Variablen zu vergleichen.
Joel Carneiro
4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}
ConroyP
quelle
4
if ('function' === typeof callback) ...
Andrew Hedges
quelle
3
Ein bisschen pedantisch und verwendet immer noch ein String-Literal. Wie wäre es if(typeof Function === typeof callback)...? :)
Jason Bunting
@ JasonBunting Neugierig, was ist falsch an der Verwendung von String-Literal?
Bsienn
@Bsienn - wie gesagt, es ist pedantisch von mir, aber hier ist die Sache. Angenommen, Sie verwenden den Code mit dem Zeichenfolgenliteral und den Aufruf, typeofspäter etwas anderes zurückzugeben (möglicherweise "Funktion" anstelle von "Funktion"), aufgrund einer neuen / anderen Implementierung von JavaScript - es scheint , dass dies weniger wahrscheinlich ist Eine neue / andere Implementierung würde die typeof Function === typeof callbackPrüfung unterbrechen, da sie auf semantischer Ebene gleich sein sollte.
Jason Bunting
4
typeof(callback) == "function"
dashtinejad
quelle
4

Ich könnte tun

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

Ich weiß, dass es eine akzeptierte Antwort gibt, aber niemand hat dies vorgeschlagen. Ich bin mir nicht sicher, ob dies zur Beschreibung von idiomatisch passt, aber es funktioniert in allen Fällen.

In neueren JavaScript-Engines finallykann stattdessen a verwendet werden.

Quentin Engles
quelle
Dies ist eine nette Abkürzung! Es funktioniert jedoch nicht nur zum Testen, ob eine Funktion vorhanden oder definiert ist (ohne sie auch auszuführen).
Beejor
Das ist richtig. Ich habe eine Situation angenommen, in der der Rückruf an diesem Ausführungspunkt optional ist. Ich benutze normalerweise typeof callbacksowieso.
Quentin Engles
Das macht Sinn; Ich habe mich mehr auf den Fragentitel als auf dessen Inhalt konzentriert. Manchmal mag ich die Einfachheit, Try-Catch über Tonnen von Tests für etwas zu verwenden. Denken Sie, dass die Verwendung einen technischen Nachteil hat, in diesem Fall gegenüber so etwas wie einem Typ? Oder geht es hauptsächlich darum, die Dinge besser / erwarteter zu machen?
Beejor
1
Wenn Sie auf mehrere Typen testen möchten, sind Ausnahmen nicht so gut. Zum Beispiel verwendet das Projekt, an dem ich gerade arbeite, viele Typprüfungen für eine Variable, um festzustellen, ob es sich um eine Funktion, eine Zeichenfolge oder was auch immer handelt. In diesem Projekt brauche ich wirklich die Typen. Dafür verwende ich eine Reihe von Typen und überprüfe accepted_types.indexOf(typeof value) !== -1, ob es sich um eine Reihe von Typen handelt. In dieser Situation wären Ausnahmen meiner Meinung nach unerschwinglich.
Quentin Engles
2

Versuche dies:

callback instanceof Function
eWolf
quelle
1
Funktioniert nicht Es wird Ihnen immer noch den Fehler geben. Sie sollten es selbst versuchen, bevor Sie es als Antwort veröffentlichen.
Vbullinger
@vbullinger Ich habe gerade noch einmal in Chrome, Firefox und Safari getestet - funktioniert überall. Mit welchem ​​Motor hatten Sie Probleme?
eWolf
Feuerfuchs. Haben Sie den Fall getestet, als kein Rückruf definiert wurde?
Vbullinger
Das ist , weil Sie eine undefinierte Variable direkt referenzieren, das nie funktioniert: pastebin.com/UQz2AmzH
eWolf
3
Es funktioniert, wenn es für einen Funktionsparameter verwendet wird, was der Autor verlangt hat. Ich nehme an, ECMAScript unterscheidet die Fälle einer nicht existierenden Variablen und einer existierenden Variablen mit dem Wert undefined. Es wäre interessant, mehr darüber zu erfahren.
eWolf
2

Wenn Sie sich die Quelle der Bibliothek @Venkat Sudheer Reddy Aedama ansehen, die unterstrichen ist, können Sie Folgendes sehen:

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

Dies ist nur mein TIPP, TIPP Antwort:>

VentyCZ
quelle
2

Versuchen:

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

Ich suchte nach einer Möglichkeit, zu überprüfen, ob eine jQuery-Funktion definiert wurde, und fand sie nicht einfach.

Vielleicht braucht es das;)

if(typeof jQuery.fn.datepicker !== "undefined")
miguelmpn
quelle
das gleiche wie type0f($.datepicker) !== undefiledsonst wirdobject
vladkras
0

Wenn callback()Sie eine Funktion nicht nur einmal aufrufen, können Sie das Argument für die Wiederverwendung initialisieren:

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

Zum Beispiel:

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

    alert(text);

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

Die Einschränkung besteht darin, dass das Rückrufargument immer ausgeführt wird, obwohl es nicht definiert ist.

Nick Tsai
quelle
0

Für globale Funktionen können Sie diese verwenden, anstatt evalsie in einer der Antworten vorzuschlagen.

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

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

Sie können auch verwenden global.f instanceof Function, aber afaik. Der Wert von Functionist in verschiedenen Frames unterschiedlich, sodass er nur mit einer einzelnen Frame-Anwendung ordnungsgemäß funktioniert. Deshalb verwenden wir normalerweise typeofstattdessen. Beachten Sie, dass in einigen Umgebungen auch Anomalien auftreten können typeof f, z. B. bei MSIE 6-8. Einige der Funktionen hatten beispielsweise alertden Typ "Objekt".

Durch lokale Funktionen können Sie die in der akzeptierten Antwort verwenden. Sie können testen, ob die Funktion auch lokal oder global ist.

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

Um die Frage zu beantworten, funktioniert der Beispielcode in den neuesten Browsern fehlerfrei für mich, daher bin ich mir nicht sicher, wo das Problem lag:

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

Hinweis: Ich würde callback !== undefinedanstelle von verwenden callback != null, aber sie tun fast das gleiche.

inf3rno
quelle
0

Die meisten, wenn nicht alle vorherigen Antworten haben Nebenwirkungen, um die Funktion aufzurufen

hier Best Practice

Sie haben Funktion

function myFunction() {
        var x=1;
    }
direkter Weg, um es zu testen

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
Verwenden Sie eine Zeichenfolge, damit Sie nur einen Ort zum Definieren des Funktionsnamens haben können

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

TexWiller
quelle
0

Wenn Sie Funktionen neu definieren möchten, verwenden Sie am besten Funktionsvariablen, die in der Reihenfolge ihres Auftretens definiert sind, da Funktionen global definiert sind, unabhängig davon, wo sie auftreten.

Beispiel für die Erstellung einer neuen Funktion, die eine vorherige gleichnamige Funktion aufruft:

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

Das hat bei mir funktioniert

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

Einzeilige Lösung:

function something_cool(text, callback){
    callback && callback();
}
Samir Alajmovic
quelle
Sein Beispiel zeigt genau das, dass er möchte, dass die Funktion aufgerufen wird, wenn sie definiert ist, und wenn dies nicht der Fall ist, passiert nichts. jsfiddle.net/nh1cxxg6 Funktionen, die Falsey / False-Werte zurückgeben, werden weiterhin aufgerufen. Dies funktioniert natürlich nicht, wenn Werte zurückgegeben werden sollen.
Samir Alajmovic
Ah, ich habe seine Frage falsch verstanden. Dies würde jedoch eine Ausnahme verursachen, wenn der Rückruf keine Funktion ist.
Frank Bryce