Bagaimana cara mengetahui apakah fungsi JavaScript didefinisikan

302

Bagaimana Anda tahu jika suatu fungsi dalam JavaScript didefinisikan?

Saya ingin melakukan sesuatu seperti ini

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

Tapi itu membuat saya

panggilan balik bukan fungsi

kesalahan saat panggilan balik tidak ditentukan.

Aaron Lee
sumber

Jawaban:

475
typeof callback === "function"
Tom Ritter
sumber
47
Ini bukan benar-benar string ajaib, karena set nilai typeof didefinisikan secara tepat dalam spesifikasi ECMA. Meskipun sintaks untuk ini sedikit konyol untuk memulai, itu adalah Javascript idiomatis yang masuk akal.
Ben Zotto
2
@quixoto - mengerti, saya kira apa yang saya maksud adalah bahwa Anda masih perlu memiliki string apa pun - Saya lebih suka tidak memiliki string literal yang mengotori kode saya daripada yang dibutuhkan; oleh karena itu, ini bukan ideal saya untuk menguji apakah ada fungsi
Jason Bunting
4
Dan ya, "sihir" adalah pilihan kata yang ceroboh dan buruk - maksudku "string literal" bukan "string ajaib." Salahku. :)
Jason Bunting
1
JSPerf - jsperf.com/...
Chris GW Green
Pastikan untuk menghapus tanda kurung pada fungsi Anda dan hanya menggunakan nama fungsi dalam kondisi-if atau fungsi akan dipanggil alih-alih memberikan Anda benar atau salah.
Russell Strauss
236

Semua jawaban saat ini menggunakan string literal, yang saya lebih suka tidak ada dalam kode saya jika mungkin - ini tidak (dan memberikan makna semantik yang berharga, untuk boot):

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

Secara pribadi, saya mencoba untuk mengurangi jumlah string yang berkeliaran di kode saya ...


Juga, sementara saya sadar itu typeofadalah operator dan bukan fungsi, ada sedikit bahaya dalam menggunakan sintaks yang membuatnya muncul sebagai yang terakhir.

Jason Bunting
sumber
7
Bagaimana saya bisa menggunakan fungsi ini? Saya sudah mencoba di isFunction(not_defined))mana not_definednama fungsi yang tidak didefinisikan dan FireBug kembali not_defined is not definedyang benar tetapi fungsi Anda harus mengembalikan false dan tidak menghasilkan kesalahan ...
Wookie88
@ Wookie88: Secara teknis, fungsi yang diilustrasikan dalam jawaban saya tidak menghasilkan kesalahan sebanyak kesalahan terjadi karena penerjemah JavaScript mencoba menyelesaikan simbol not_defineduntuk meneruskan nilainya isFunction()dan gagal menyelesaikannya. Tidak ada yang bisa dilakukan untuk definisi isFunction()untuk menyelesaikan masalah ini.
Jason Bunting
3
@ZacharyYates Cara untuk bekerja di sekitar ReferenceError berarti menghindari bekerja dengan referensi ke fungsi yang mungkin tidak didefinisikan. Anda bisa melakukan pemeriksaan ketik di dalam panggilan fungsi dan meneruskan hasilnya ke fungsi. jsfiddle.net/qNaxJ Mungkin tidak begitu baik, tapi setidaknya, tidak ada string yang digunakan;)
netiul
8
Atau hindari fungsi isFunctiondan lakukan saja (typeof no_function == typeof Function).
netiul
2
@JasonBunting Jika Anda akan pilih-pilih, Anda benar-benar harus menggunakan typeof(Function())karena Fungsi adalah fungsi; tetapi begitu juga Array, Object, dan prototipe bawaan lainnya (karena tidak ada istilah yang lebih baik). Jika Anda memeriksa array yang tidak akan Anda gunakan typeof(array) === typeof(Array)misalnya; Anda akan menggunakan typeof(array) === typeof(Array())karena Anda benar-benar perlu mengevaluasi fungsi jika Anda berhati-hati dan konsisten.
seanmhanson
16
if (callback && typeof(callback) == "function")

Catatan panggilan balik itu (dengan sendirinya) mengevaluasi ke falsejika undefined, null, 0, atau false. Membandingkan dengan nullterlalu spesifik.

Robin suka burung
sumber
2
Perhatikan juga bahwa jika ia callbacksendiri mengevaluasi ke nilai "false-y", maka tipenya tidak akan pernah menjadi "fungsi".
Joe
5
@ Jo, tetapi karena hubungan arus pendek, tes itu tidak akan dilakukan jika panggilan balik bernilai false.
Fabio A.
3
solusi ini tidak berfungsi, karena kondisi pertama akan memunculkan pengecualian segera. ini bisa berfungsi, untuk properti objek: if (obj.callback) {...}
Roey
8

Metode-metode untuk mengetahui apakah suatu fungsi diimplementasikan juga gagal jika variabel tidak didefinisikan sehingga kami menggunakan sesuatu yang lebih kuat yang mendukung penerimaan string:

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

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}
patriciorocca
sumber
Saya pikir ini adalah jawaban yang bagus, Anda benar, semua metode di atas gagal adalah fungsi tidak didefinisikan.
Matteo Conta
Ini sepele untuk menghindari referensi yang tidak terdefinisi - cukup merujuk typeof window.doesthisexistsebagai ganti doesthisexist. Namun, menggunakan eval (yang: jahat) seperti yang ditunjukkan hanya akan berfungsi dengan fungsi bernama - ini tidak akan berfungsi dengan kasus penggunaan dalam pertanyaan.
AD7six
Ketahuilah bahwa ini hanya berfungsi dengan cakupan global, sementara jawaban yang diterima bekerja dengan fungsi lingkup lokal juga.
inf3rno
6

Baru mengenal JavaScript Saya tidak yakin apakah perilakunya telah berubah tetapi solusi yang diberikan oleh Jason Bunting (6 tahun yang lalu) tidak akan berfungsi jika mungkinFungsi tidak didefinisikan.

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

Ini akan menimbulkan ReferenceError: possibleFunction is not definedkesalahan saat mesin mencoba untuk menyelesaikan simbolFungsi (seperti yang disebutkan dalam komentar untuk jawaban Jason)

Untuk menghindari perilaku ini, Anda hanya dapat meneruskan nama fungsi yang ingin Anda periksa jika ada. Begitu

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

Ini menetapkan variabel menjadi fungsi yang ingin Anda periksa atau objek kosong jika tidak ditentukan dan menghindari masalah yang disebutkan di atas.

NectarSoft
sumber
Untuk sepenuhnya jelas: kode saya tidak membuang kesalahan, itu hanya pengurai JavaScript yang melakukan itu. Hal yang sama akan terjadi jika Anda mencoba menggunakan pengidentifikasi yang tidak terdefinisi sedemikian rupa.
Jason Bunting
6

Mencoba:

if (typeof(callback) == 'function')
bdukes
sumber
HI, jangan gunakan perbandingan "longgar" (==) selalu gunakan '===' untuk membandingkan bahkan jenis variabel.
Joel Carneiro
4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}
ConroyP
sumber
4
if ('function' === typeof callback) ...
Andrew Hedges
sumber
3
Sebuah bit bertele-tele, dan masih menggunakan literal string yang. Bagaimana dengan if(typeof Function === typeof callback)...? :)
Jason Bunting
@JasonBunting Penasaran, Apa yang salah dengan menggunakan string literal?
Bsienn
@ Bsienn - seperti yang saya katakan, ini sangat menyebalkan bagi saya, tapi inilah masalahnya. Katakanlah Anda menggunakan kode dengan string literal, dan panggilan untuk typeofmengembalikan sesuatu yang berbeda di kemudian hari (mungkin "Function" alih-alih "function"), karena implementasi JavaScript yang baru / berbeda - rasanya seperti kecil kemungkinannya bahwa implementasi baru / berbeda akan mematahkan typeof Function === typeof callbackpemeriksaan karena harus sama di tingkat semantik.
Jason Bunting
4
typeof(callback) == "function"
dashtinejad
sumber
4

Mungkin saya lakukan

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

Saya tahu ada jawaban yang diterima, tetapi tidak ada yang menyarankan ini. Saya tidak begitu yakin apakah ini cocok dengan deskripsi idiomatik, tetapi ini berfungsi untuk semua kasus.

Dalam mesin JavaScript yang lebih baru, a finallydapat digunakan sebagai gantinya.

Quentin Engles
sumber
Ini jalan pintas yang rapi! Meskipun itu tidak akan berfungsi hanya untuk menguji apakah ada fungsi atau didefinisikan (tanpa juga menjalankannya).
Beejor
Itu benar. Saya berasumsi situasi di mana callback adalah opsional pada titik eksekusi itu. Saya biasanya menggunakan typeof callbackpula.
Quentin Engles
Itu masuk akal; Saya lebih fokus pada judul pertanyaan daripada kontennya. Kadang-kadang saya suka kesederhanaan menggunakan try-catch over banyak tes untuk sesuatu. Apakah Anda pikir ada kerugian teknis untuk menggunakannya, dalam hal ini versus sesuatu seperti typeof? Atau itu terutama masalah melakukan sesuatu dengan cara yang lebih tepat / diharapkan?
Beejor
1
Jika Anda ingin menguji beberapa jenis, pengecualian tidak terlalu bagus. Sebagai contoh, proyek yang sedang saya kerjakan sekarang menggunakan banyak jenis pengecekan pada satu variabel untuk melihat apakah itu fungsi, string, atau apa pun. Dalam proyek ini saya sangat membutuhkan tipenya. Untuk ini saya menggunakan berbagai jenis, dan memeriksa accepted_types.indexOf(typeof value) !== -1untuk melihat apakah itu dalam berbagai jenis. Dalam situasi ini pengecualian menurut saya akan menjadi penghalang.
Quentin Engles
2

Coba ini:

callback instanceof Function
eWolf
sumber
1
Tidak bekerja Itu masih akan memberi Anda kesalahan. Anda harus mencobanya sendiri sebelum mempostingnya sebagai jawaban.
vbullinger
@vbullinger Saya baru saja menguji lagi di Chrome, Firefox dan Safari - berfungsi di mana-mana. Dengan mesin mana Anda mengalami masalah?
eWolf
Firefox. Apakah Anda menguji kasus ini ketika panggilan balik tidak ditentukan?
vbullinger
Itu karena Anda secara langsung mereferensikan variabel tidak terdefinisi, yang tidak pernah berfungsi: pastebin.com/UQz2AmzH
eWolf
3
Itu berfungsi ketika digunakan pada parameter fungsi, yang adalah apa yang penulis minta - Saya kira ECMAScript membedakan kasus-kasus variabel yang tidak ada dan variabel yang ada dengan nilai yang tidak ditentukan. Akan menarik untuk mengetahui lebih banyak tentang ini.
eWolf
2

Jika Anda melihat sumber perpustakaan @Venkat Sudheer Reddy Aedama yang disebutkan, underscorejs, Anda dapat melihat ini:

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

Ini hanya PETUNJUK saya, PETUNJUK jawaban:>

VentyCZ
sumber
2

Mencoba:

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

Saya sedang mencari cara untuk memeriksa apakah fungsi jQuery didefinisikan dan saya tidak menemukannya dengan mudah.

Mungkin mungkin membutuhkannya;)

if(typeof jQuery.fn.datepicker !== "undefined")
miguelmpn
sumber
sama seperti type0f($.datepicker) !== undefiledsebaliknyaobject
vladkras
0

Jika callback()Anda memanggil bukan hanya untuk satu kali dalam suatu fungsi, Anda bisa menginisialisasi argumen untuk digunakan kembali:

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

Sebagai contoh:

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

    alert(text);

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

Batasannya adalah ia akan selalu mengeksekusi argumen callback meskipun tidak terdefinisi.

Nick Tsai
sumber
0

Untuk fungsi global, Anda dapat menggunakan yang ini alih-alih evaldisarankan dalam salah satu jawaban.

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

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

Anda bisa menggunakan global.f instanceof Functionjuga, tapi afaik. nilai Functionakan berbeda dalam bingkai yang berbeda, sehingga hanya akan berfungsi dengan aplikasi bingkai tunggal dengan benar. Itu sebabnya kami biasanya menggunakan typeofsebagai gantinya. Perhatikan bahwa dalam beberapa lingkungan dapat terjadi anomali typeof fjuga, misalnya oleh MSIE 6-8 beberapa fungsi misalnya alertmemiliki tipe "objek".

Dengan fungsi-fungsi lokal, Anda dapat menggunakannya di jawaban yang diterima. Anda dapat menguji apakah fungsinya juga lokal atau global.

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

Untuk menjawab pertanyaan, kode contoh berfungsi untuk saya tanpa kesalahan di peramban terbaru, jadi saya tidak yakin apa masalahnya dengan itu:

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

Catatan: Saya akan menggunakan callback !== undefinedsebagai gantinya callback != null, tetapi mereka melakukan hampir sama.

inf3rno
sumber
0

Sebagian besar jika tidak semua jawaban sebelumnya memiliki efek samping untuk menjalankan fungsi

di sini praktik terbaik

Anda memiliki fungsi

function myFunction() {
        var x=1;
    }
cara langsung untuk menguji itu

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
menggunakan string sehingga Anda hanya dapat memiliki satu tempat untuk mendefinisikan nama fungsi

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

TexWiller
sumber
0

Jika Anda ingin mendefinisikan kembali fungsi, yang terbaik adalah menggunakan variabel fungsi, yang didefinisikan dalam urutan kejadiannya, karena fungsi didefinisikan secara global, di mana pun mereka terjadi.

Contoh membuat fungsi baru yang memanggil fungsi sebelumnya dengan nama yang sama:

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

Ini berhasil untuk saya

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

Solusi satu baris:

function something_cool(text, callback){
    callback && callback();
}
Samir Alajmovic
sumber
Teladannya menunjukkan hanya itu, bahwa ia ingin fungsi dipanggil jika itu didefinisikan, dan jika tidak, tidak ada yang terjadi. jsfiddle.net/nh1cxxg6 Fungsi yang mengembalikan nilai falsey / false masih dipanggil. Tentu saja, ini tidak berfungsi ketika Anda ingin nilai dikembalikan.
Samir Alajmovic
Ah, saya salah membaca pertanyaannya. Namun, ini akan menyebabkan pengecualian jika panggilan balik bukan suatu fungsi.
Frank Bryce