Bagaimana cara memanggil metode bernama dinamis di Javascript?

113

Saya sedang mengerjakan secara dinamis membuat beberapa JavaScript yang akan dimasukkan ke dalam halaman web saat sedang dibuat.

JavaScript akan digunakan untuk mengisi listboxberdasarkan pilihan di tempat lain listbox. Ketika pemilihan salah satu listboxdiubah, itu akan memanggil nama metode berdasarkan nilai yang dipilih dari listbox.

Sebagai contoh:

Listbox1 mengandung:

  • Colours
  • Shapes

Jika Coloursdipilih maka itu akan memanggil populate_Coloursmetode yang mengisi yang lain listbox.

Untuk memperjelas pertanyaan saya: Bagaimana cara melakukan populate_Colourspanggilan itu di JavaScript?

Chris B
sumber
Saya akan merekomendasikan untuk tidak melakukannya demi memiliki cabang lokal dalam satu metode 'populate'. Ini akan membuatnya lebih mudah diuji dan terlihat tidak terlalu "hacky"
Aaron Powell
lihat jawaban saya di sini. panggil dengan nama dalam javascript
Hugo R

Jawaban:

208

Dengan asumsi populate_Coloursmetode ini dalam namespace global, Anda dapat menggunakan kode berikut, yang mengeksploitasi bahwa semua properti objek dapat diakses seolah-olah objek adalah array asosiatif, dan bahwa semua objek global sebenarnya adalah properti windowobjek host.

var method_name = "Colours";
var method_prefix = "populate_";

// Call function:
window[method_prefix + method_name](arg1, arg2);
Triptych
sumber
9
Terima kasih atas tanggapannya. Bit 'jendela' benar-benar menghantam saya sampai saya mencari di Google dan menemukan bahwa objek global adalah bagian dari objek jendela. Sekarang masuk akal! Terima kasih. FYI saya menemukan halaman yang bagus tentang itu di sini devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Chris B
3
Saya melakukan sesuatu yang serupa kecuali fungsi yang saya targetkan berada di namespace "fn" jQuery. Misalnya,$.fn[method_prefix + method_name](arg1, arg2);
codecraig
1
Bagus. Layak menambahkan try/ catchblok, mungkin.
LeeGee
Ini mungkin jelas bagi sebagian orang, tetapi bagi mereka yang tidak dapat membuatnya berfungsi: buang fungsi di luar kode $(function () {dan Anda window.load:)
Stan Smulders
1
@peter Karena tanda kurung siku bukanlah pengakses properti dalam konteks ini, tetapi menunjukkan Array. Array bukanlah fungsi, jadi Anda tidak bisa memanggilnya.
user4642212
39

Seperti yang ditunjukkan Triptych, Anda dapat memanggil fungsi cakupan global apa pun dengan menemukannya di konten objek host.

Metode yang lebih bersih, yang mencemari namespace global jauh lebih sedikit, adalah dengan secara eksplisit meletakkan fungsi ke dalam array secara langsung seperti:

var dyn_functions = [];
dyn_functions['populate_Colours'] = function (arg1, arg2) { 
                // function body
           };
dyn_functions['populate_Shapes'] = function (arg1, arg2) { 
                // function body
           };
// calling one of the functions
var result = dyn_functions['populate_Shapes'](1, 2);
// this works as well due to the similarity between arrays and objects
var result2 = dyn_functions.populate_Shapes(1, 2);

Array ini juga bisa menjadi properti dari beberapa objek selain objek host global yang juga berarti Anda dapat secara efektif membuat namespace Anda sendiri seperti yang dilakukan oleh banyak library JS seperti jQuery. Ini berguna untuk mengurangi konflik jika / saat Anda menyertakan beberapa pustaka utilitas terpisah di halaman yang sama, dan (bagian lain dari desain Anda mengizinkan) dapat mempermudah penggunaan kembali kode di halaman lain.

Anda juga bisa menggunakan objek seperti itu, yang mungkin Anda temukan lebih bersih:

var dyn_functions = {};
dyn_functions.populate_Colours = function (arg1, arg2) { 
                // function body
           };
dyn_functions['populate_Shapes'] = function (arg1, arg2) { 
                // function body
           };
// calling one of the functions
var result = dyn_functions.populate_Shapes(1, 2);
// this works as well due to the similarity between arrays and objects
var result2 = dyn_functions['populate_Shapes'](1, 2);

Perhatikan bahwa dengan array atau objek, Anda dapat menggunakan salah satu metode pengaturan atau mengakses fungsi, dan tentu saja dapat menyimpan objek lain di sana juga. Anda selanjutnya dapat mengurangi sintaks dari salah satu metode untuk konten yang tidak terlalu dinamis dengan menggunakan notasi literal JS seperti ini:

var dyn_functions = {
           populate_Colours:function (arg1, arg2) { 
                // function body
           };
         , populate_Shapes:function (arg1, arg2) { 
                // function body
           };
};

Sunting: tentu saja untuk blok fungsionalitas yang lebih besar Anda dapat memperluas di atas ke "pola modul" yang sangat umum yang merupakan cara populer untuk merangkum fitur kode secara terorganisir.

David Spillett
sumber
Itu cara yang bagus untuk menjaganya tetap bersih. Bagaimana saya menyebut metode ini? Akankah window [dyn_functions ['populate_Colours'] (arg1, arg2) berfungsi?
Chris B
Menjawab pertanyaan saya sendiri - Saya baru saja menguji window [dyn_functions ['populate_Colours'] (arg1, arg2)]; dan itu memang berhasil.
Chris B
4
Seperti yang ditunjukkan oleh epascarello, Anda biasanya tidak memerlukan "window" - "dyn_functions ['populate_Colours'] (arg1, arg2);" akan bekerja. Faktanya, tidak menyertakan nama objek global akan membuat kode lebih portabel jika Anda menulis rutinitas yang mungkin pernah digunakan di lingkungan JS selain browser web. Ada pengecualian untuk ini: jika Anda memiliki variabel lokal yang disebut dyn_functions dalam sebuah fungsi maka Anda harus lebih spesifik yang Anda maksud, tetapi situasi ini sebaiknya dihindari (dengan memiliki konvensi penamaan yang masuk akal).
David Spillett
1
Karena posting ini berasal dari '09 Anda mungkin sudah tahu ini sekarang, tetapi Anda sedang membuat array, lalu menetapkan ke properti array (bukan indeks). Anda mungkin juga melakukannya var dyn_functions = {};sehingga Anda tidak perlu membuat larik ... ini bukan masalah besar.
David Sherret
jawaban yang terlalu rumit tetapi berhasil. Saya akan berpikir beban sumber daya untuk skenario di mana saya memiliki serangkaian fungsi berpola dan saya memerlukan pohon keputusan untuk memilih eksekusi, metode ini mungkin terlalu kompleks untuk melakukan tugas tersebut. Meskipun, jika saya memasang kabel objek kelas saya sendiri, ini akan menjadi pendekatan yang lebih disukai untuk mendefinisikan objek itu sendiri.
GoldBishop
30

Saya akan merekomendasikan untuk TIDAK menggunakan global/ window/ evaluntuk tujuan ini.
Sebaliknya, lakukan dengan cara ini:

mendefinisikan semua metode sebagai properti Handler:

var Handler={};

Handler.application_run = function (name) {
console.log(name)
}

Sekarang sebut saja seperti ini

var somefunc = "application_run";
Handler[somefunc]('jerry');

Hasil keluaran: jerigen

JerryGoyal
sumber
17

Anda bisa melakukannya seperti ini:

function MyClass() {
    this.abc = function() {
        alert("abc");
    }
}

var myObject = new MyClass();
myObject["abc"]();
Simon
sumber
5

Di dalam ServiceWorkeratau Worker, ganti windowdengan self:

self[method_prefix + method_name](arg1, arg2);

Pekerja tidak memiliki akses ke DOM, oleh karena windowitu referensi tidak valid. Pengenal cakupan global yang setara untuk tujuan ini adalah self.

OKSIGEN
sumber
2

Saya tidak akan merekomendasikan menggunakan jendela seperti yang disarankan beberapa jawaban lain. Gunakan thisdan ruang lingkup yang sesuai.

this['yourDynamicFcnName'](arguments);

Trik rapi lainnya adalah memanggil dalam cakupan yang berbeda dan menggunakannya untuk warisan. Katakanlah Anda telah menumpuk fungsi dan menginginkan akses ke objek jendela global. Anda bisa melakukan ini:

this['yourDynamicFcnName'].call(window, arguments);
Tim Moses
sumber
1

Hai coba ini,

 var callback_function = new Function(functionName);
 callback_function();

itu akan menangani parameter itu sendiri.

mathi
sumber
kesalahan referensi yang tidak tertangkap - functionName tidak ditentukan
brianlmerritt
@ Brianlmerritt Anda harus menentukan nilai untuk functionName... penjawab membuat asumsi bahwa Anda sudah menetapkannya.
GoldBishop
Tampaknya Fungsi baru () tidak dapat digunakan seperti itu untuk tujuan ini.
JCH77
-1

Berikut adalah solusi yang berfungsi dan sederhana untuk memeriksa keberadaan suatu fungsi dan triaging fungsi tersebut secara dinamis oleh fungsi lain;

Fungsi pemicu

function runDynmicFunction(functionname){ 

    if (typeof window[functionname] == "function"  ) { //check availability

        window[functionname]("this is from the function it "); //run function and pass a parameter to it
    }
}

dan sekarang Anda dapat menghasilkan fungsi secara dinamis mungkin menggunakan php seperti ini

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

sekarang Anda dapat memanggil fungsi tersebut menggunakan peristiwa yang dibuat secara dinamis

<?php

$name_frm_somware ="runThis_func";

echo "<input type='button' value='Button' onclick='runDynmicFunction(\"".$name_frm_somware."\");'>";

?>

kode HTML yang Anda butuhkan adalah

<input type="button" value="Button" onclick="runDynmicFunction('runThis_func');">
Aylian Craspa
sumber
-3

Coba dengan ini:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Gilberto
sumber
Apa implikasi dari penggunaan pola ini? Saya telah membaca bahwa evalfungsi tersebut memiliki beberapa efek samping aneh terkait dengan penggunaannya. Saya biasanya mencoba untuk menjauh darinya, kecuali itu adalah pilihan terakhir.
GoldBishop