Überprüfen Sie, ob eine Variable vom Funktionstyp ist

904

Angenommen, ich habe eine Variable, die wie folgt definiert ist:

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

Ich möchte eine Funktion, die prüft, ob der Typ der Variablen funktionsähnlich ist. dh:

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

Wie kann ich auf die oben definierte Weise überprüfen, ob die Variable avom Typ ist Function?

Jesufer Vn
quelle
2
Hier ein Benchmark für diese gängigsten Methoden, um dies zu überprüfen. jsben.ch/#/e5Ogr
EscapeNetscape

Antworten:

380

Sicher, der Weg des Unterstrichs ist effizienter, aber der beste Weg, um zu überprüfen, ob Effizienz kein Problem ist, ist auf der von @Paul Rosania verlinkten Seite des Unterstrichs zu finden.

Inspiriert vom Unterstrich lautet die endgültige isFunction-Funktion wie folgt:

function isFunction(functionToCheck) {
 return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
Alex Grande
quelle
1
Es mag jemanden geben, der sich eingehender mit diesem Thema befasst hat, aber schauen Sie sich die Ergebnisse von Revision 4 des jsperf mit einfacher "Ergebnisüberprüfung" an . isFunctionAzeigt einen Implementierungsunterschied zu den anderen Methoden.
Joel Purra
24
Bei aktualisierten Leistungstests scheint es je nach Browser einen großen Geschwindigkeitsunterschied zu geben. In Chrome typeof(obj) === 'function'scheint es bei weitem das schnellste zu sein; In Firefox obj instanceof Functionist jedoch der klare Gewinner.
Justin Warkentin
7
In Bezug auf das Teil: typeof sollte nur verwendet werden, um zu überprüfen, ob Variablen oder Eigenschaften undefiniert sind. Unter javascript.info/tutorial/type-detection im Abschnitt A good use of typeof und im folgenden Abschnitt gibt der Autor an, dass der Fall genau umgekehrt ist
Konrad Madej
11
Alex, ich bin gespannt, warum du sagst, dass typeof nur verwendet werden sollte, um nach Undefinierten zu suchen. Der Name deutet darauf hin, dass der Zweck darin besteht, den Typ von etwas zu überprüfen, nicht nur, ob es existiert. Gibt es technische Probleme oder Probleme, die bei der Verwendung zur Typprüfung auftreten können, oder ist dies eher eine Präferenz? Wenn es Vorbehalte gibt, ist es gut, sie aufzulisten, damit andere vermeiden können, über sie zu stolpern.
Jinglesthula
14
unangemessen überkomplizierte Lösung
Daniel Garmoshka
1712
if (typeof v === "function") {
    // do something
}
Selbie
quelle
44
Just watch out für ein paar Dinge wie typeof Object, typeof Date, und typeof String, die alle Rückkehr 'function'zu.
Dave Ward
358
@ Dave, ich bin nicht sicher, was das Problem ist, da dies Funktionen sind.
Matthew Crumley
6
Was ist der Unterschied zu if (v instanceOf Function)?
mquandalle
10
@mquandalle Kein großer Unterschied, außer instanceoffunktioniert nicht, wenn Sie eine Funktion überprüfen, die aus einem anderen Dokument stammt (möglicherweise einem Iframe). Die Leistung variiert.
Rvighne
8
Im Gegensatz zur akzeptierten Antwort funktioniert dies auch für asynchrone Funktionen. Für ein asyncfunctionToCheck, getType.toString.call(functionToCheck)==='[object AsyncFunction]'wo alstypeof asyncfunctionToCheck === 'function'
TDreama
132

Underscore.js verwendet einen aufwändigeren, aber hochleistungsfähigen Test:

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

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

BEARBEITEN: Aktualisierte Tests deuten darauf hin, dass der Typ möglicherweise schneller ist (siehe http://jsperf.com/alternative-isfunction-implementations/4)

Paul Rosania
quelle
Gibt es einen bestimmten Grund für diesen Ansatz als typof?
sv_in
1
Die Version von Underscore ist in den meisten Browsern viel schneller. Siehe: jsperf.com/alternative-isfunction-implementations
Paul Rosania
13
Ich mag Unterstriche, einfach, aber kraftvoll. Das heißt, es ist wahrscheinlich erwähnenswert, dass diese Implementierung durch ein Objekt mit diesen Attributen gefälscht werden könnte.
Studgeek
3
@PaulRosania Stolperte heute über diese Leistungstests und aktualisierte sie mit Überprüfung und weiteren Testdaten als Revision 4 - führen Sie sie aus, um die Abdeckung der Browsertests zu erhöhen. Der Betrieb pro Sekunde ist langsamer (aufgrund der vielen Tests), zeigt jedoch auch einen Implementierungsunterschied (öffnen Sie Ihre Javascript-Konsole und laden Sie die Seite neu, es werden möglicherweise Fehlermeldungen protokolliert). Hinweis: In Revision 3 wurde isFunctionD hinzugefügt (nur basierend auf typeof == "function") - und es scheint viel schneller zu sein als die "schnelle" Version von Underscore.
Joel Purra
6
Diese Antwort ist jetzt etwas irreführend, da sich Underscore.js jetzt in Revision 12 und nicht in der oben genannten Revision 4 des Tests alternativer isFunction()Implementierungen befindet. Derzeit wird etwas verwendet, das dem sehr nahe kommt, was Dandean vorgeschlagen hat.
Jonathan Eunice
112

Es gibt verschiedene Möglichkeiten, also werde ich sie alle zusammenfassen

  1. Der beste Weg ist:
    Funktion foo (v) {if (v Instanz der Funktion) {/ * etwas tun * /}};
    
    
    Die leistungsstärkste (kein Zeichenfolgenvergleich) und elegante Lösung - die Instanz des Operators wird in Browsern schon sehr lange unterstützt, also keine Sorge - sie funktioniert in IE 6.
  2. Der nächstbeste Weg ist:
    Funktion foo (v) {if (typeof v === "function") {/ * mach etwas * /}};
    
    
    Nachteil von typeof ist, dass es anfällig für stille Fehler ist, schlecht, wenn Sie also einen Tippfehler haben (z. B. "Finction") - in diesem Fall gibt das "if" nur false zurück und Sie werden erst später wissen, dass Sie einen Fehler haben dein Code
  3. Der nächstbeste Weg ist:
    Funktion isFunction (functionToCheck) {
        var getType = {};
        return functionToCheck && getType.toString.call (functionToCheck) === '[Objektfunktion]';
    }}
    
    
    Dies hat keinen Vorteil gegenüber Lösung Nr. 1 oder Nr. 2, ist jedoch viel weniger lesbar. Eine verbesserte Version davon ist
    Funktion isFunction (x) {
        return Object.prototype.toString.call (x) == '[Objektfunktion]';
    }}
    
    
    aber immer noch viel weniger semantisch als Lösung Nr. 1
Dalimian
quelle
10
Die erste Lösung schlägt fehl, wenn eine Funktion an einen anderen Rahmenkontext übergeben wird. Zum Beispiel aus einem Iframe top.Function !== Function. Verwenden Sie zur Sicherheit die zweite (hoffentlich wird jede Rechtschreibfehler von "function" beim Debuggen korrigiert).
MaxArt
In Bezug auf Tippfehler: Jeder Code mit diesem Tippfehler schlägt wahrscheinlich schnell fehl / ist nicht offensichtlicher als alle anderen Fehler, die auf Tippfehlern basieren. typeof === "function" ist die sauberste Lösung. Darüber hinaus instanceofberücksichtigt Ihre „beste“ Lösung, die Sie verwenden , nicht mehrere globale Werte, z. B. eine Prüfung über Frames hinweg, und kann falsch negative Ergebnisse zurückgeben.
Brainkim
84

jQuery (veraltet seit Version 3.3) Referenz

$.isFunction(functionName);

AngularJS Referenz

angular.isFunction(value);

Lodash Referenz

_.isFunction(value);

Unterstreichende Referenz

_.isFunction(object); 

Node.js ist seit der Referenz v4.0.0 veraltet

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

@grandecomplex: Ihre Lösung ist ziemlich ausführlich. Es wäre viel klarer, wenn man so schreiben würde:

function isFunction(x) {
  return Object.prototype.toString.call(x) == '[object Function]';
}
Dandean
quelle
Object.prototype.toString.call ist nützlich für andere Javascript-Typen, an denen Sie interessiert sind. Sie können sogar gegen null oder undefiniert prüfen, was es sehr leistungsfähig macht.
Jason Foglia
49

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

wsc
quelle
1
... und (() => (typeof obj === 'function') && doSomething())ist immer noch die schnellste Option.
Darcher
35

Versuchen Sie den instanceofOperator: Es scheint, dass alle Funktionen von der FunctionKlasse erben :

// 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
quelle
19

Etwas mit mehr Browserunterstützung und auch asynchronen Funktionen könnte sein:

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

und dann testen Sie es wie:

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
quelle
11

Ein anderer einfacher Weg:

var fn = function () {}
if (fn.constructor === Function) {
  // true
} else {
  // false
}
GuillaumeL
quelle
1
Wenn fn undefiniert ist, wird ein Fehler ausgelöst
Kamil Orzechowski
fn && fn.constructor === FunctionWie wäre es damit?
Jaroslaw Melnichuk
9

Für diejenigen, die sich für funktionalen Stil interessieren oder nach einem ausdrucksstärkeren Ansatz für die Metaprogrammierung suchen (z. B. Typprüfung), könnte es interessant sein, Ramda zu sehen Bibliothek zu sehen, um eine solche Aufgabe zu erfüllen.

Der nächste Code enthält nur reine und punktfreie Funktionen:

const R = require('ramda');

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

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

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

Ab ES2017 sind asyncFunktionen verfügbar, sodass wir sie auch überprüfen können:

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

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

Und dann kombinieren Sie sie zusammen:

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

Natürlich sollte die Funktion gegen nullund undefinedWerte geschützt werden, um sie "sicher" zu machen:

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

Und ein vollständiger Ausschnitt, um es zusammenzufassen:

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

Beachten Sie jedoch, dass diese Lösung aufgrund der umfangreichen Verwendung von Funktionen höherer Ordnung möglicherweise eine geringere Leistung als andere verfügbare Optionen aufweist.

Beschädigtes Bio
quelle
7

Wenn Sie Lodash verwenden, können Sie dies mit _.isFunction tun .

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

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

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

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

Diese Methode gibt zurück, truewenn value eine Funktion ist false.

Slorenzo
quelle
4

Ich fand , dass bei der Prüfung von nativen Browser - Funktionen in IE8, mit toString, instanceofund typeofhabe nicht funktioniert. Hier ist eine Methode, die in IE8 gut funktioniert (soweit ich weiß):

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

Alternativ können Sie nach nativen Funktionen suchen, indem Sie:

"getElementById" in document

Allerdings habe ich irgendwo gelesen, dass dies in IE7 und darunter nicht immer funktioniert.

Azmisov
quelle
4

Das Folgende scheint auch für mich zu funktionieren (getestet von node.js):

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

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

Ich denke, Sie können einfach ein Flag für den Funktionsprototyp definieren und prüfen, ob die zu testende Instanz dies geerbt hat

Flag definieren:

Function.prototype.isFunction = true; 

und überprüfen Sie dann, ob es existiert

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

Der Nachteil ist, dass ein anderer Prototyp das gleiche Flag definieren kann und es dann wertlos ist. Wenn Sie jedoch die volle Kontrolle über die enthaltenen Module haben, ist dies der einfachste Weg

Danny Mor
quelle
Es wird mit Fehler fehlschlagen, wenn foo undefiniert ist. Ganz zu schweigen davon, dass Sie den nativen Prototyp modifizieren, was völlig falsch ist.
Kamil Orzechowski
3

Seit Knoten v0.11 können Sie die Standard-Util-Funktion verwenden:

var util = require('util');
util.isFunction('foo');
Moklick
quelle
2
util.isFunction ist veraltet
kehers
2

Sie sollten den typeOfOperator in js verwenden.

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

Wie einige frühere Antworten gezeigt haben, besteht die Lösung darin, typeof zu verwenden. Das Folgende ist ein Code-Snippet in 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
quelle