Bir JavaScript işlevinin tanımlanıp tanımlanmadığı nasıl anlaşılır


302

JavaScript'te bir işlevin tanımlanıp tanımlanmadığını nasıl anlarsınız?

Böyle bir şey yapmak istiyorum

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

Ama bu bana

geri arama bir işlev değildir

geri arama tanımlanmadığında hata.

Yanıtlar:


475
typeof callback === "function"

47
Bu gerçekten sihirli bir dize değildir, çünkü typeof değerleri kümesi ECMA spesifikasyonunda tam olarak tanımlanmıştır. Bunun sözdizimi ile başlamak biraz aptalca olsa da, son derece makul deyimsel Javascript.
Ben Zotto 30'10

2
@quixoto - anlaşılır, ne demek istediğimi hala hala bir dize olması gerektiğini - Ben kesinlikle gerekenden daha kodumu çöp daha fazla literal dizeleri olmaz; bu nedenle, bir şeyin bir işlev olup olmadığını test etmek için bu benim idealim değil.
Jason Bunting

4
Ve evet, "büyü" özensiz, kötü bir kelime seçimiydi - "sihirli dize" değil, "gerçek dize" demek istedim. Benim hatam. :)
Jason Bunting


İşlevinizdeki parantezin kaldırıldığından emin olun ve işlev koşulunu yalnızca if-koşulunda kullanın, aksi takdirde size true veya false vermek yerine işlev çağrılır.
Russell Strauss

236

Geçerli yanıtların tümü, mümkünse kodumda olmamayı tercih ettiğim değişmez bir dize kullanır - bu yoktur (ve önyükleme yapmak için değerli anlamsal anlam sağlar):

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

Şahsen, kodumda takılan dizelerin sayısını azaltmaya çalışıyorum ...


Ayrıca, typeofbir işlevin değil, bir işleç olduğunun farkında olduğum halde, sözdizimini kullanmanın, ikincisi olarak görünmesini sağlayan çok az zarar vardır.


7
Bu işlevi nasıl kullanmam gerekiyor? Ben tanımlı değil fonksiyonun adı isFunction(not_defined))nerede denedim not_definedve FireBug not_defined is not defineddoğru olanı döndü ama sizin fonksiyonu yanlış dönmelidir ve hata
üretmemelidir

@ Wookie88: Teknik olarak, cevabımda gösterilen işlev bir hata oluştuğu kadar bir hata döndürmüyor çünkü JavaScript yorumlayıcısı, not_defineddeğerini iletmek için sembolü çözmeye çalışıyor ve çözemedi isFunction(). isFunction()Bu sorunu çözmek için hiçbir şey yapılamaz .
Jason Bunting

3
@ZacharyYates ReferenceError etrafında çalışmanın yolu, belki tanımlanmamış işleve bir başvuru ile çalışmaktan kaçınmak anlamına gelir. İşlev çağrısının içindeki daktilo kontrolünü yapabilir ve sonucu işleve iletebilirsiniz. jsfiddle.net/qNaxJ Belki çok hoş değil, ama en azından dizeler kullanılmış;)
netiul

8
Veya bir işlevden kaçının isFunctionve sadece yapın (typeof no_function == typeof Function).
netiul

2
@JasonBunting Eğer bu seçici olacaksanız, gerçekten typeof(Function())bir işlev olduğu için kullanmak gerekir ; ancak Array, Object ve diğer yerleşik prototipler de (daha iyi bir terim olmaması nedeniyle). Örneğin bir diziyi kontrol ediyor olsaydınız typeof(array) === typeof(Array); Kullanmak istediğiniz typeof(array) === typeof(Array())dikkatli ve tutarlı olup olmadıklarını kontrol aslında fonksiyonunu değerlendirmek gerekir çünkü.
seanmhanson

16
if (callback && typeof(callback) == "function")

Değerlendirir için (tek başına) olup bir geri arama Not falsebu ise undefined, null, 0ya da false. İle karşılaştırmak nullaşırı belirgin.


2
Ayrıca, callbackkendisi "false-y" değeri olarak değerlendirilirse, typeof işlevinin asla "function" olamayacağını unutmayın .
Joe

5
@Joe, ancak kısa devre nedeniyle, geri arama yanlış olarak değerlendirilirse bu test yapılmayacaktır.
Fabio

3
bu çözüm işe yaramıyor çünkü ilk koşul hemen bir istisna oluşturacak. bu, bir nesnenin bir özelliği için işe yarayabilir: if (obj.callback) {...}
Roey

8

Bir işlevin uygulanıp uygulanmadığını söylemek için kullanılan yöntemler, değişken tanımlanmadıysa da başarısız olur, böylece bir dize almayı destekleyen daha güçlü bir şey kullanırız:

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

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}

Bence iyi bir cevap, haklısın, yukarıdaki tüm yöntemler başarısız olduğu fonksiyon tanımlanmamıştır.
Matteo Conta

1
Tanımlanmamış referanslardan kaçınmak önemsizdir - typeof window.doesthisexistbunun yerine bakın doesthisexist. Ancak, eval (hangi: kötü) gösterildiği gibi kullanıldığında yalnızca adlandırılmış işlevlerle çalışır - bu, söz konusu kullanım örneğiyle çalışmaz.
AD7six

Bunun yalnızca küresel kapsamla çalıştığını, kabul edilen cevabın da yerel kapsam işlevleriyle çalıştığını unutmayın.
inf3rno

6

JavaScript'te yeni Davranışın değişip değişmediğinden emin değilim, ancak Jason Bunting (6 yıl önce) tarafından verilen çözüm mümkünse çalışmaz.

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

Bu bir ReferenceError: possibleFunction is not defined , motor olası sembolü çözmeye çalıştığında hata (yorumlarda Jason'ın cevabına belirtildiği gibi)

Bu davranışı önlemek için yalnızca var olup olmadığını kontrol etmek istediğiniz işlevin adını iletebilirsiniz. Yani

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

Bu, bir değişkeni kontrol etmek istediğiniz işlev veya tanımlanmamışsa boş nesne olarak ayarlar ve bu nedenle yukarıda belirtilen sorunları önler.


Tamamen açık olmak gerekirse: kodum hata atmıyor, bu sadece JavaScript ayrıştırıcısını yapıyor. Tanımsız bir tanımlayıcıyı bu şekilde kullanmaya çalıştığınızda da aynı şey olur.
Jason Bunting

6

Deneyin:

if (typeof(callback) == 'function')

HI, "gevşek" karşılaştırmayı kullanmayın (==) değişkenin türünü bile karşılaştırmak için her zaman '===' kullanın.
Joel Carneiro

4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}

4
if ('function' === typeof callback) ...

3
Bir bit bilgiçlik ve hala bir dize kullanır. Nasıl if(typeof Function === typeof callback)...? :)
Jason Bunting

@JasonBunting Meraklı, dizgi değişmezi kullanmanın yanlışlığı nedir?
Bsienn

@Bsienn - dediğim gibi, benim bilgiçim, ama işte bu. Let Diyelim ki dize ile kodunu ve telefon görüşmesinde demek typeofo - çünkü JavaScript yeni / farklı uygulama, daha sonra döner farklı bir şey (yerine "işlevi" belki "Fonksiyon") hissediyor daha az olası olurdu gibi yeni / farklı bir uygulama, typeof Function === typeof callbacksemantik düzeyde aynı olması gerektiği için denetimi kırabilir .
Jason Bunting


4

yapabilirim

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

Kabul edilmiş bir cevap olduğunu biliyorum, ama kimse bunu önermedi. Bunun deyimsel açıklamaya uyup uymadığından emin değilim, ancak tüm durumlar için çalışıyor.

Daha yeni JavaScript motorlarında finallybunun yerine a kullanılabilir.


Bu temiz bir kısayoldur! Gerçi bir fonksiyonun var olup olmadığını veya tanımlandığını test etmek için işe yaramaz (aynı zamanda onu çalıştırmadan).
Beejor

Bu doğru. Bu yürütme noktasında geri aramanın isteğe bağlı olduğu bir durum olduğunu varsaydım. Ben genellikle typeof callbackher halükarda kullanırım .
Quentin Engles

Mantıklı; Soru başlığına içeriğinden daha fazla odaklanıyordum. Bazen bir şey için tonlarca testin üzerinde deneme yakalamanın basitliğini seviyorum. Bunu kullanmanın teknik bir dezavantajı olduğunu düşünüyor musunuz, bu durumda typeof gibi bir şeye karşı? Yoksa esas olarak işleri daha doğru / beklenen bir şekilde yapmak mı?
Beejor

1
Birden fazla türü test etmek istiyorsanız, istisnalar o kadar iyi değildir. Örneğin şu anda üzerinde çalıştığım proje, bir işlev, dize veya başka bir şey olup olmadığını görmek için bir değişken üzerinde çok fazla tür denetimi kullanıyor. Bu projede gerçekten türlere ihtiyacım var. Bunun için bir dizi türü kullanıyorum ve bir dizi türde olup olmadığını kontrol accepted_types.indexOf(typeof value) !== -1ediyorum. Bu durumda, istisnalar bence yasaklayıcı olacaktır.
Quentin Engles

2

Bunu dene:

callback instanceof Function

1
Çalışmıyor. Yine de size hata verecektir. Cevap olarak göndermeden önce kendiniz denemelisiniz.
vbullinger

@vbullinger Chrome, Firefox ve Safari'de tekrar test ettim - her yerde çalışıyor. Hangi motorla sorun yaşadınız?
eWolf

Firefox. Geri arama tanımlanmadığında durumu test ettiniz mi?
vbullinger

Bunun nedeni, doğrudan tanımlanmamış bir değişkene doğrudan
başvurmanızdır

3
Yazarın istediği şey olan bir işlev parametresinde kullanıldığında çalışır - ECMAScript'in var olmayan bir değişkenin ve tanımlanmamış bir değere sahip mevcut bir değişkenin durumlarını ayırt ettiğini varsayalım. Bu konuda daha fazla bilgi edinmek ilginç olurdu.
eWolf

2

@Venkat Sudheer Reddy Aedama'nın bahsettiği kütüphanenin kaynağına bakarsanız , underscorejs, bunu görebilirsiniz:

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

Bu sadece benim İPUCU, İPUCU cevabım:


2

Deneyin:

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


1

Nasıl bir jQuery işlevi tanımlanmış olup olmadığını kontrol etmek için bakıyordu ve ben kolayca bulamadık.

Belki de buna ihtiyaç duyabilir;)

if(typeof jQuery.fn.datepicker !== "undefined")

aynı type0f($.datepicker) !== undefiledaksi olacakobject
vladkras

0

Eğer callback()bir fonksiyonun içinde sadece bir kez değil çağırarak, sen yeniden kullanım için argüman ilklendireceğiniz:

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

Örneğin:

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

    alert(text);

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

Sınırlama, tanımlanmamış olmasına rağmen her zaman geri çağrı bağımsız değişkenini yürütmesidir.


0

Global işlevler için eval, cevaplardan birinde önerilen yerine bunu kullanabilirsiniz .

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

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

global.f instanceof FunctionAfaik de kullanabilirsiniz . değerinin değeri Functionfarklı çerçevelerde farklı olacaktır, bu nedenle yalnızca tek bir çerçeve uygulamasıyla düzgün çalışacaktır. Bu yüzden genellikle kullanıyoruz typeof. Bazı ortamlarda typeof f, örneğin MSIE 6-8 ile bazı fonksiyonların alert"nesne" tipine sahip olabileceğini unutmayın .

Yerel işlevlerle kabul edilen cevaptaki işlevi kullanabilirsiniz. Fonksiyonun yerel mi yoksa global mi olduğunu test edebilirsiniz.

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

Soruyu cevaplamak için, örnek kod en son tarayıcılarda hatasız benim için çalışıyor, bu yüzden sorunun ne olduğundan emin değilim:

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

Not: Bunun callback !== undefinedyerine kullanırdım callback != null, ama neredeyse aynı şeyi yapıyorlar.


0

Daha önceki tüm cevapların işlevi çağırmak için yan etkileri olmasa da çoğu

burada en iyi uygulama

fonksiyonun var

function myFunction() {
        var x=1;
    }
test etmenin doğrudan yolu

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
işlev adını tanımlamak için yalnızca bir yeriniz olması için bir dize kullanma

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


0

İşlevleri yeniden tanımlamak isterseniz, işlevler, gerçekleştikleri yere bakılmaksızın, küresel olarak tanımlandığından, gerçekleşme sıralarında tanımlanan işlev değişkenlerini kullanmak en iyisidir.

Aynı adda önceki bir işlevi çağıran yeni bir işlev oluşturma örneği:

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

0

Bu benim için çalıştı

if( cb && typeof( eval( cb ) ) === "function" ){
    eval( cb + "()" );
}

-2

Tek hat çözümü:

function something_cool(text, callback){
    callback && callback();
}

Onun örneği sadece bunu gösterir, eğer tanımlanmışsa işlevin çağrılmasını ister ve eğer değilse, hiçbir şey olmaz. jsfiddle.net/nh1cxxg6 Falsey / false değerleri döndüren işlevler hala çağrılır. Tabii ki, değerlerin döndürülmesini istediğinizde bu işe yaramaz.
Samir Alajmovic

Ah, sorusunu yanlış okudum. Ancak, geri arama bir işlev değilse bu bir istisnaya neden olur.
Frank Bryce
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.