Değişkenin işlev türünde olup olmadığını kontrol edin


904

Aşağıdaki gibi tanımlanan herhangi bir değişkenim olduğunu varsayalım:

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

Değişkenin türünün işlev benzeri olup olmadığını kontrol eden bir işlev istiyorum. yani:

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

Değişkenin yukarıda tanımlandığı şekilde atür olup olmadığını nasıl kontrol edebilirim Function?


Yanıtlar:


380

Emin alt çizginin yolu daha verimlidir, ancak verimlilik bir sorun olmadığında kontrol etmenin en iyi yolu, alt çizginin @Paul Rosania tarafından bağlanan sayfasında yazılır.

Alt çizgiden esinlenerek, son isFunction işlevi aşağıdaki gibidir:

function isFunction(functionToCheck) {
 return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}

1
Konuyla ilgili daha kapsamlı araştırmalar yapmış, ancak basit "sonuç doğrulaması" ile jsperf'in 4. düzeltmesinin sonuçlarına bir göz atan biri olabilir . isFunctionAdiğer yöntemlere göre uygulama farkı gösterir.
Joel Purra

24
Güncellenmiş performans testleri ile tarayıcınıza bağlı olarak büyük bir hız farkı var gibi görünüyor. Chrome'da açık typeof(obj) === 'function'arayla en hızlı gibi görünüyor; ancak, Firefox'ta obj instanceof Functionaçık kazanan.
Justin Warkentin

7
Parça ile ilgili olarak: typeof yalnızca değişkenlerin veya özelliklerin tanımsız olup olmadığını kontrol etmek için kullanılmalıdır. At javascript.info/tutorial/type-detection içinde typeof iyi bir kullanımı vaka tam tersi olduğunu bölümüne aşağıdaki biri yazar devletler,
Konrad Madej

11
Alex, merak ediyorum, niçin typeof dediğini sadece tanımsız olup olmadığını kontrol etmek için kullanmalısın. Adı, amacının sadece var olup olmadığını değil, bir şeyin türünü kontrol etmek olduğunu göstermektedir. Tür denetimi yapmak için kullanıldığında ortaya çıkabilecek teknik sorunlar veya sorunlar var mı, yoksa daha çok tercih ediliyor mu? Uyarılar varsa, bunları listelemek iyi olur, böylece diğerleri onları takmaktan kaçınabilir.
jinglesthula

14
makul olmayan bir şekilde aşırı karmaşık çözüm
Daniel Garmoshka

1712
if (typeof v === "function") {
    // do something
}

44
Tıpkı bir kaç şey için dikkat typeof Object, typeof Dateve typeof String, hangi tüm iade 'function'de.
Dave Ward

358
@Dave, fonksiyonlar olduğundan sorunun ne olduğundan emin değilim.
Matthew Crumley

6
Aradaki fark nedir if (v instanceOf Function)?
mquandalle

10
@mquandalle Büyük bir fark yok, ancak instanceofbaşka bir belgeden gelen bir işlevi (iframe, belki) kontrol ederseniz çalışmaz. Performans değişiklik gösterir.
rvighne

8
kabul edilen cevabın aksine bu asenkron fonksiyonlar için de geçerlidir. Bir yerde asyncfunctionToCheck, getType.toString.call(functionToCheck)==='[object AsyncFunction]'olduğu gibitypeof asyncfunctionToCheck === 'function'
TDreama

132

Underscore.js daha ayrıntılı ancak yüksek performanslı bir test kullanır:

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

Bkz. Http://jsperf.com/alternative-isfunction-implementations

DÜZENLEME: güncellenen testler, yazım yönteminin daha hızlı olabileceğini düşündürmektedir, bkz. Http://jsperf.com/alternative-isfunction-implementations/4


Bu yaklaşımı kullanmak için özel bir neden var mı typof?
sv_in

1
Undercore'un sürümü çoğu tarayıcıda çok daha hızlıdır. Bakınız: jsperf.com/alternative-isfunction-implementations
Paul Rosania

13
Ben altını çizmek istiyorum, basit ama güçlü. Bununla birlikte, muhtemelen bu uygulamanın bu niteliklere sahip bir nesne tarafından aldatılabileceğini belirtmek gerekir.
studgeek

3
@PaulRosania Bu performans testlerini bugün erkenden tökezledi ve bunları doğrulama artı revizyon 4 olarak daha fazla test verisiyle güncelledi - tarayıcı testi kapsamını artırmak için lütfen çalıştırın. Saniyedeki işlemlerde daha yavaştır (birçok test nedeniyle), ancak bir uygulama farkı da gösterir (javascript konsolunuzu açın ve sayfayı yeniden yükleyin, günlüğe kaydedilen hata mesajları olabilir). Not: Revizyon 3 eklenmiştir isFunctionD (yalnızca tabanlı typeof == "function") - ve Underscore'un "hızlı" versiyonundan çok daha hızlı görünüyor .
Joel Purra

6
Bu cevap şimdi biraz yanıltıcıdır, çünkü Underscore.js, alternatif uygulamalar testinin yukarıda belirtilen revizyon 4'ünde değil, revizyon 12'deisFunction() . Şu anda dandeanın önerisine çok yakın bir şey kullanıyor .
Jonathan Eunice

112

Birkaç yol var, bu yüzden hepsini özetleyeceğim

  1. En iyi yol:
    function foo (v) {if (v instanceof Function) {/ * bir şeyler yapın * /}};
    
    
    Çoğu performans (dize karşılaştırması yok) ve zarif çözüm - instanceof operatörü tarayıcılarda çok uzun zamandır desteklenmektedir, bu yüzden endişelenmeyin - IE 6'da çalışacaktır.
  2. Bir sonraki en iyi yol:
    function foo (v) {if (typeof v === "function") {/ * bir şeyler yapın * /}};
    
    
    dezavantajı, typeofsessiz hataya duyarlı olması, kötü, bu yüzden bir yazım hatası varsa (örneğin "finction") - bu durumda `if 'sadece yanlış dönecek ve daha sonraya kadar bir hatanız olduğunu bilmeyeceksiniz senin kodun
  3. Bir sonraki en iyi yol:
    function isFunction (functionToCheck) {
        var getType = {};
        return functionToCheck && getType.toString.call (functionToCheck) === '[nesne İşlevi]';
    }
    
    
    Bunun çözüm # 1 veya # 2'ye göre bir avantajı yoktur, ancak çok daha az okunabilir. Bunun geliştirilmiş bir sürümü
    işlev isFunction (x) {
        Object.prototype.toString.call (x) == '[nesne İşlevi]';
    }
    
    
    ancak çözüm # 1'den çok daha az anlamsal

10
Farklı bir çerçeve içeriğine geçen bir işlev durumunda ilk çözüm başarısız olur. Örneğin, bir iframe'den top.Function !== Function. Emin olmak için ikincisini kullanın ("işlev" in herhangi bir yanlış yazımı, hata ayıklama sırasında düzeltilir, umarım).
MaxArt

Yazım hatalarıyla ilgili olarak: bu yazım hatası olan herhangi bir kodun hızlı bir şekilde başarısız olması muhtemeldir / yazım hatalarına dayalı diğer hatalardan daha belirgin değildir. typeof === "fonksiyon" en temiz çözümdür. Ek olarak, kullandığınız “en iyi” çözümünüz instanceof, kareler arasında bir kontrol gibi birden fazla globali dikkate almaz ve yanlış negatifler döndürebilir.
brainkim


56

@grandecomplex: Çözümünüzde makul miktarda ayrıntı var. Böyle yazılırsa çok daha açık olur:

function isFunction(x) {
  return Object.prototype.toString.call(x) == '[object Function]';
}

Object.prototype.toString.call, ilgilendiğiniz diğer javascript türleri için kullanışlıdır. Hatta null veya undefined ile karşılaştırarak çok güçlü hale getirebilirsiniz.
Jason Foglia

49

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


1
... ve (() => (typeof obj === 'function') && doSomething())hala en hızlı seçenek.
darcher

35

instanceofİşleci deneyin : Tüm işlevler Functionsınıftan miras alıyor gibi görünüyor :

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

19

Daha fazla tarayıcı desteği olan ve aynı zamanda zaman uyumsuz işlevler içeren bir şey olabilir:

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

ve sonra şöyle test edin:

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


9

İşlevsel stille ilgilenenler veya meta programlamada (tip kontrolü gibi) kullanmak için daha anlamlı bir yaklaşım arayanlar için, bu tür bir görevi yerine getirmek için Ramda kütüphanesini görmek ilginç olabilir .

Sonraki kod yalnızca saf ve noktasız işlevler içerir:

const R = require('ramda');

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

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

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

ES2017'den itibaren asyncfonksiyonlar mevcuttur, böylece bunlara karşı da kontrol edebiliriz:

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

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

Ve sonra bunları birleştirin:

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

Tabii ki, işlev "güvenli" hale getirmek için nullve undefineddeğerlere karşı korunmalıdır :

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

Ve özetlemek için snippet'i tamamlayın:

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

Bununla birlikte, bu çözümün, üst düzey işlevlerin yaygın kullanımı nedeniyle mevcut diğer seçeneklerden daha az performans gösterebileceğini unutmayın.


7

Lodash kullanıyorsanız _.isFunction ile yapabilirsiniz .

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

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

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

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

trueDeğer başka bir işlevse bu yöntem geri döner false.


4

Ben IE8'de yerel tarayıcı işlevlerini test ederken, kullanıyor ise toString, instanceofve typeofçalışma yoktu. İşte (bildiğim kadarıyla) IE8 iyi çalışan bir yöntem:

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

Alternatif olarak, aşağıdakileri kullanarak yerel işlevleri kontrol edebilirsiniz:

"getElementById" in document

Yine de, bir yerde bunun her zaman IE7 ve altında çalışmayacağını okudum.


4

Aşağıdakiler benim için de işe yarıyor gibi görünüyor (denenmiştir node.js):

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

console.log(isFunction(function(){})); // true
console.log(isFunction({})); // false

4

İşlev prototipinde bir bayrak tanımlayabileceğinizi ve test etmek istediğiniz örneğin miras alıp almadığını kontrol edebileceğinizi düşünüyorum

bir bayrak tanımlayın:

Function.prototype.isFunction = true; 

ve sonra var olup olmadığını kontrol et

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

Dezavantajı, başka bir prototipin aynı bayrağı tanımlayabilmesidir ve daha sonra değersizdir, ancak dahil edilen modüller üzerinde tam kontrole sahipseniz, bu en kolay yoldur


Foo tanımsızsa Hata ile başarısız olur. Tamamen yanlış olan yerel prototipi değiştirdiğinizden bahsetmiyorum.
Kamil Orzechowski

3

V0.11 düğümünden bu yana, standart util işlevini kullanabilirsiniz:

var util = require('util');
util.isFunction('foo');

2
util.isFunction kullanımdan kaldırıldı
kehers

2

js'de typeOfoperatör kullanmalısınız .

var a=function(){
    alert("fun a");
}
alert(typeof a);// alerts "function"

0

Önceki bazı cevapların gösterdiği çözüm, typeof kullanmaktır. NodeJs'de bir kod snippet'i aşağıdadır,

    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]();
  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.