Apakah ada cara untuk mendapatkan nama parameter fungsi dari suatu fungsi secara dinamis?
Katakanlah fungsi saya terlihat seperti ini:
function doSomething(param1, param2, .... paramN){
// fill an array with the parameter name and value
// some other code
}
Sekarang, bagaimana cara saya mendapatkan daftar nama parameter dan nilainya ke dalam array dari dalam fungsi?
javascript
reflection
function-parameter
vikasde
sumber
sumber
function doSomething(...args) { /*use args*/}
Jawaban:
Fungsi berikut akan mengembalikan array nama parameter dari setiap fungsi yang diteruskan.
Contoh penggunaan:
Edit :
Dengan ditemukannya ES6 fungsi ini dapat tersandung oleh parameter default. Ini adalah peretasan cepat yang seharusnya bisa digunakan dalam kebanyakan kasus:
Saya mengatakan sebagian besar kasus karena ada beberapa hal yang akan menjebaknya
Sunting : Saya juga mencatat vikasde menginginkan nilai parameter dalam array juga. Ini sudah disediakan dalam variabel lokal bernama argumen.
kutipan dari https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments :
Objek argumen bukan Array. Ini mirip dengan Array, tetapi tidak memiliki properti Array kecuali panjang. Misalnya, tidak memiliki metode pop. Namun itu dapat dikonversi menjadi Array nyata:
Jika Array generics tersedia, seseorang dapat menggunakan yang berikut ini sebagai gantinya:
sumber
var fn = function(a /* fooled you)*/,b){};
akan menghasilkan["a", "/*", "fooled", "you"]
Di bawah ini adalah kode yang diambil dari AngularJS yang menggunakan teknik untuk mekanisme injeksi ketergantungannya.
Dan berikut ini penjelasannya diambil dari http://docs.angularjs.org/tutorial/step_05
sumber
annotate = angular.injector.$$annotate
Berikut ini adalah solusi terbaru yang berupaya menangani semua kasus tepi yang disebutkan di atas dengan cara yang ringkas:
Output tes singkat (contoh uji lengkap terlampir di bawah):
Tampilkan cuplikan kode
sumber
return (func+'') .replace(/[/][/].*$/mg,'') // strip single-line comments (line-ending sensitive, so goes first) .replace(/\s+/g,'') // remove whitespace
func + ''
denganFunction.toString.call(func)
untuk mempertahankan kasus ketika fungsi memiliki implementasi .toString () kustom..split(/\)[\{=]/, 1)[0]
({ a, b, c })
) ke semua parameter di dalam destrukturisasi. untuk menjaga benda yang rusak tetap utuh, ubah yang terakhir.split
ke:.split(/,(?![^{]*})/g)
Solusi yang lebih sedikit rawan kesalahan terhadap spasi dan komentar adalah:
sumber
Banyak jawaban di sini menggunakan regex, ini bagus tapi tidak terlalu baik untuk penambahan bahasa (seperti fungsi panah dan kelas). Yang juga perlu diperhatikan adalah bahwa jika Anda menggunakan salah satu dari fungsi ini pada kode yang diperkecil maka ia akan pergi 🔥. Itu akan menggunakan apa pun nama yang diperkecil itu. Sudut menyiasatinya dengan memungkinkan Anda untuk mengirimkan serangkaian string yang cocok dengan urutan argumen saat mendaftarkannya dengan wadah DI. Demikian seterusnya dengan solusinya:
Ini menangani masalah parse asli dan beberapa tipe fungsi lainnya (mis. Fungsi panah). Inilah gagasan tentang apa yang bisa dan tidak bisa ditangani sebagaimana adanya:
Bergantung pada apa yang ingin Anda gunakan untuk ES6 Proxy dan perusakan mungkin merupakan pilihan terbaik Anda. Misalnya jika Anda ingin menggunakannya untuk injeksi dependensi (menggunakan nama params) maka Anda dapat melakukannya sebagai berikut:
Ini bukan resolver paling canggih di luar sana tetapi memberikan gambaran tentang bagaimana Anda dapat menggunakan Proxy untuk menanganinya jika Anda ingin menggunakan args parser untuk DI sederhana. Namun ada satu peringatan kecil dalam pendekatan ini. Kita perlu menggunakan penugasan yang merusak alih-alih params yang normal. Ketika kami melewati proxy injector, destrukturisasi sama dengan memanggil pengambil pada objek.
Ini menghasilkan sebagai berikut:
Ini menghubungkan seluruh aplikasi. Bit terbaik adalah bahwa aplikasi ini mudah untuk diuji (Anda bisa langsung membuat instance setiap kelas dan lulus mengejek / bertopik / dll). Juga jika Anda perlu menukar implementasi, Anda dapat melakukannya dari satu tempat. Semua ini dimungkinkan karena objek JS Proxy.
Catatan: Ada banyak pekerjaan yang perlu dilakukan untuk ini sebelum akan siap untuk penggunaan produksi tetapi itu memberikan gambaran seperti apa bentuknya.
Ini agak terlambat dalam jawabannya tetapi mungkin membantu orang lain yang memikirkan hal yang sama. 👍
sumber
Saya tahu ini adalah pertanyaan lama, tetapi pemula telah meniru ini seolah-olah ini adalah praktik yang baik dalam kode apa pun. Sebagian besar waktu, harus mengurai representasi string fungsi untuk menggunakan nama parameternya hanya menyembunyikan kesalahan dalam logika kode.
Parameter fungsi sebenarnya disimpan dalam objek mirip array yang disebut
arguments
, di mana argumen pertama adalaharguments[0]
, yang kedua adalaharguments[1]
dan seterusnya. Menulis nama parameter dalam tanda kurung dapat dilihat sebagai sintaks steno. Ini:...sama dengan:
Variabel itu sendiri disimpan dalam ruang lingkup fungsi, bukan sebagai properti dalam objek. Tidak ada cara untuk mengambil nama parameter melalui kode karena itu hanya simbol yang mewakili variabel dalam bahasa manusia.
Saya selalu menganggap representasi string dari fungsi sebagai alat untuk keperluan debugging, terutama karena
arguments
objek seperti array ini . Anda tidak diharuskan untuk memberikan nama pada argumen di tempat pertama. Jika Anda mencoba mem-parsing fungsi yang dirangkai, itu tidak benar-benar memberi tahu Anda tentang parameter tambahan tanpa nama yang mungkin diperlukan.Inilah situasi yang bahkan lebih buruk dan lebih umum. Jika suatu fungsi memiliki lebih dari 3 atau 4 argumen, mungkin logis untuk meneruskannya sebagai objek, yang lebih mudah untuk dikerjakan.
Dalam hal ini, fungsi itu sendiri akan dapat membaca objek yang diterimanya dan mencari propertinya serta mendapatkan nama dan nilainya, tetapi mencoba mengurai representasi string dari fungsi tersebut hanya akan memberi Anda "keberatan" untuk parameter, yang tidak berguna sama sekali.
sumber
Function.prototype.toString = function () { return 'function () { [native code] }'; };
Proxy
( perangkap konstruktor dan menerapkan perangkap ) danReflection
untuk menangani DI untuk beberapa modul saya. Itu cukup solid.Karena JavaScript adalah bahasa scripting, saya merasa bahwa introspeksinya harus mendukung mendapatkan nama parameter fungsi. Punting pada fungsionalitas itu merupakan pelanggaran prinsip pertama, jadi saya memutuskan untuk mengeksplorasi masalah lebih lanjut.
Itu mengarahkan saya ke pertanyaan ini tetapi tidak ada solusi bawaan. Yang mengarahkan saya ke jawaban ini yang menjelaskan bahwa
arguments
hanya usang di luar fungsi, sehingga kami tidak dapat lagi menggunakanmyFunction.arguments
atau mendapatkan:Saatnya menyingsingkan lengan baju kami dan mulai bekerja:
⭐ Mengambil parameter fungsi memerlukan parser karena ekspresi kompleks seperti
4*(5/3)
dapat digunakan sebagai nilai default. Jadi jawaban Gaafar atau jawaban James Drew sejauh ini merupakan pendekatan terbaik.Saya mencoba parser babylon dan esprima tetapi sayangnya mereka tidak dapat mengurai fungsi anonim yang berdiri sendiri, seperti yang ditunjukkan dalam jawaban Mateusz Charytoniuk . Saya menemukan solusi lain dengan mengelilingi kode di dalam tanda kurung, agar tidak mengubah logika:
Baris baru mencegah masalah dengan
//
(komentar satu baris).⭐ Jika parser tidak tersedia, opsi terbaik berikutnya adalah menggunakan teknik coba-dan-benar seperti Angular.js's dependency injector regular expressions. Saya menggabungkan versi fungsional jawaban Lambder dengan jawaban humbletim dan menambahkan
ARROW
boolean opsional untuk mengendalikan apakah fungsi panah lemak ES6 diizinkan oleh ekspresi reguler.Berikut adalah dua solusi yang saya kumpulkan. Perhatikan bahwa ini tidak memiliki logika untuk mendeteksi apakah suatu fungsi memiliki sintaks yang valid, mereka hanya mengekstrak argumen. Ini biasanya ok karena kita biasanya melewatkan fungsi yang diuraikan
getArguments()
sehingga sintaksnya sudah valid.Saya akan mencoba mengumpulkan solusi ini sebaik mungkin, tetapi tanpa upaya dari pengelola JavaScript, ini akan tetap menjadi masalah terbuka.
Versi Node.js (tidak dapat dijalankan hingga StackOverflow mendukung Node.js):
Contoh kerja penuh:
https://repl.it/repls/SandybrownPhonyAngles
Versi browser (perhatikan bahwa ia berhenti pada nilai default kompleks pertama):
Contoh kerja penuh:
https://repl.it/repls/StupendousShowyOffices
sumber
Saya telah membaca sebagian besar jawabannya di sini, dan saya ingin menambahkan satu kalimat.
atau
atau untuk fungsi satu-liner di ECMA6
__
Katakanlah Anda memiliki fungsi
Kode di bawah ini akan kembali
"abc,def,ghi,jkl"
Kode itu juga akan berfungsi dengan pengaturan fungsi yang diberikan Camilo Martin :
Juga dengan komentar Bubersson tentang jawaban Jack Allan :
__
Penjelasan
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
Ini menciptakan Ekspresi Reguler dengan
new RegExp('(?:'+Function.name+'\\s*|^)\\s*\\((.*?)\\)')
. Saya harus menggunakannew RegExp
karena saya menyuntikkan variabel (Function.name
, nama fungsi yang ditargetkan) ke dalam RegExp.Contoh Jika nama fungsi adalah "foo" (
function foo()
), RegExp akan menjadi/foo\s*\((.*?)\)/
.Function.toString().replace(/\n/g, '')
Kemudian itu mengubah seluruh fungsi menjadi string, dan menghapus semua baris baru. Menghapus baris baru membantu pengaturan fungsi yang diberikan Camilo Martin .
.exec(...)[1]
Ini
RegExp.prototype.exec
fungsinya. Ini pada dasarnya cocok dengan Eksponen Reguler (new RegExp()
) ke dalam String (Function.toString()
). Kemudian[1]
akan mengembalikan Kelompok Pengambilan pertama yang ditemukan dalam Eksponen Reguler ((.*?)
)..replace(/\/\*.*?\*\//g, '').replace(/ /g, '')
Ini akan menghapus setiap komentar di dalam
/*
dan*/
, dan menghapus semua spasi.Ini juga sekarang mendukung
=>
fungsi membaca dan memahami tanda panah ( ), sepertif = (a, b) => void 0;
, yangFunction.toString()
akan mengembalikan(a, b) => void 0
fungsi yang normalfunction f(a, b) { return void 0; }
. Ekspresi reguler asli akan membuat kesalahan dalam kebingungannya, tetapi sekarang diperhitungkan.Perubahan adalah dari
new RegExp(Function.name+'\\s*\\((.*?)\\)')
(/Function\s*\((.*?)\)/
) kenew RegExp('(?:'+Function.name+'\\s*|^)\\((.*?)\\)')
(/(?:Function\s*|^)\((.*?)\)/
)Jika Anda ingin menjadikan semua parameter menjadi Array alih-alih String yang dipisahkan oleh koma, pada akhirnya tambahkan saja
.split(',')
.sumber
f = (a, b) => void 0
; padagetParameters(f)
saya dapatkanTypeError: Cannot read property '1' of null
getParameters(a => b => c => d => a*b*c*d)
, yang dengan kode Anda masih memberikan ituTypeError: Cannot read property '1' of null
... sedangkan yang ini berfungsi stackoverflow.com/a/29123804=> ["a", "b", "c"]
sumber
Anda juga dapat menggunakan parser "esprima" untuk menghindari banyak masalah dengan komentar, spasi putih, dan hal-hal lain di dalam daftar parameter.
Ia bekerja bahkan dengan kode seperti ini:
sumber
Saya sudah mencoba melakukan ini sebelumnya, tetapi tidak pernah menemukan cara praktis untuk menyelesaikannya. Saya akhirnya melewati sebuah objek dan kemudian mengulanginya.
sumber
Saya tidak tahu apakah solusi ini sesuai dengan masalah Anda, tetapi ini memungkinkan Anda mendefinisikan kembali fungsi apa pun yang Anda inginkan, tanpa harus mengubah kode yang menggunakannya. Panggilan yang ada akan menggunakan params yang diposisikan, sedangkan implementasi fungsi dapat menggunakan "params bernama" (parameter hash tunggal).
Saya pikir Anda akan tetap memodifikasi definisi fungsi yang ada jadi, mengapa tidak memiliki fungsi pabrik yang membuat apa yang Anda inginkan:
Semoga ini bisa membantu.
sumber
Cara yang tepat untuk melakukan ini adalah dengan menggunakan parser JS. Berikut ini adalah contoh menggunakan biji .
Kode di sini menemukan nama-nama dari tiga (formal) parameter fungsi
f
. Ia melakukannya dengan memberi makanf
ke dalamacorn.parse()
.sumber
Saya tidak tahu cara mendapatkan daftar parameter tetapi Anda dapat melakukan ini untuk mendapatkan berapa banyak yang diharapkan.
sumber
function gotcha (a, b = false, c) {}; alert(gotcha.length)
Mengambil jawaban dari @ jack-allan saya memodifikasi fungsi sedikit untuk memungkinkan properti default ES6 seperti:
masih kembali
[ 'a', 'b' ]
sumber
Bagaimana saya biasanya melakukannya:
Anda bahkan dapat ref argumen dengan nama fungsi seperti:
Semoga ini membantu!
sumber
var args = name.arguments; console.log('I WANNa SEE', args);
menampilkan sesuatu seperti "{arg1: {...}, arg2: 'string'}"? Ini mungkin jelas hal-hal:(function fn (arg, argg, arrrrgggg) { console.log('#fn:', fn.arguments, Object.keys(fn.arguments)); }); fn('Huh...?', 'Wha...?', 'Magic...?');
. Argumen Fungsi adalah objek seperti 'Array', memiliki indeks Enumerable. Saya tidak berpikir pemetaan hash adalah mungkin, tetapi Anda bisa melewati Object-literal yang merupakan praktik yang baik jika Anda memiliki lebih dari 4 params.sumber
Jawaban untuk ini membutuhkan 3 langkah:
argValues
). Ini lurus ke depan karena akan tersediaarguments
di dalam fungsi.argNames
). Ini tidak semudah dan membutuhkan parsing fungsi. Alih-alih melakukan regex kompleks sendiri dan khawatir tentang kasus tepi (parameter default, komentar, ...), Anda dapat menggunakan perpustakaan seperti babylon yang akan menguraikan fungsi menjadi pohon sintaksis abstrak dari mana Anda dapat memperoleh nama-nama parameter.Kode akan seperti ini
dan objek yang dicatat adalah
Dan inilah contoh yang berfungsi https://tonicdev.com/5763eb77a945f41300f62a79/5763eb77a945f41300f62a7a
sumber
sumber
Wow sudah banyak jawaban .. Saya cukup yakin ini terkubur. Meski begitu saya pikir ini mungkin berguna untuk beberapa orang.
Saya tidak sepenuhnya puas dengan jawaban yang dipilih seperti pada ES6 tidak bekerja dengan baik dengan nilai default. Dan itu juga tidak memberikan informasi nilai default. Saya juga menginginkan fungsi yang ringan yang tidak bergantung pada lib eksternal.
Fungsi ini sangat berguna untuk keperluan debugging, misalnya: mencatat fungsi yang dipanggil dengan params, nilai-nilai param default dan argumen.
Saya menghabiskan beberapa waktu untuk ini kemarin, memecahkan RegExp yang tepat untuk menyelesaikan masalah ini dan inilah yang saya temukan. Ini bekerja dengan sangat baik dan saya sangat senang dengan hasilnya:
Seperti yang Anda tahu beberapa nama parameter menghilang karena Babel transpiler menghapusnya dari fungsi. Jika Anda akan menjalankan ini di NodeJS terbaru itu berfungsi seperti yang diharapkan (Hasil komentar dari NodeJS).
Catatan lain, seperti yang dinyatakan dalam komentar adalah bahwa tidak berfungsi dengan fungsi panah sebaris sebagai nilai default. Ini hanya membuatnya menjadi jauh lebih kompleks untuk mengekstraksi nilai menggunakan RegExp.
Tolong beri tahu saya jika ini bermanfaat bagi Anda! Senang mendengar umpan balik!
sumber
Saya akan memberi Anda contoh singkat di bawah ini:
sumber
Paket ini menggunakan penyusunan ulang untuk membuat AST dan kemudian nama parameter dikumpulkan dari mereka, ini memungkinkannya untuk mendukung pencocokan pola, argumen default, fungsi panah dan fitur ES6 lainnya.
https://www.npmjs.com/package/es-arguments
sumber
Saya telah memodifikasi versi yang diambil dari AngularJS yang mengimplementasikan mekanisme injeksi dependensi untuk bekerja tanpa Angular. Saya juga telah memperbarui
STRIP_COMMENTS
regex untuk bekerjaECMA6
, sehingga mendukung hal-hal seperti nilai default pada tanda tangan.sumber
Anda dapat mengakses nilai argumen yang diteruskan ke fungsi menggunakan properti "argumen".
sumber
arguments
properti instance fungsi sudah tidak digunakan lagi. Lihat developer.mozilla.org/en/Core_JavaScript_1.5_Reference/…Cukup mudah.
Pada awalnya ada yang ditinggalkan
arguments.callee
- referensi ke fungsi yang disebut. Yang kedua jika Anda memiliki referensi ke fungsi Anda, Anda dapat dengan mudah mendapatkan representasi tekstual mereka. Pada yang ketiga jika Anda memanggil fungsi Anda sebagai konstruktor Anda juga dapat memiliki tautan melalui yourObject.constructor. NB: Solusi pertama sudah usang jadi jika Anda tidak bisa tidak menggunakannya, Anda juga harus memikirkan arsitektur aplikasi Anda. Jika Anda tidak memerlukan nama variabel yang tepat, gunakan saja di dalam fungsi variabel internalarguments
tanpa sihir apa pun.https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee
Semuanya akan memanggil toString dan ganti dengan re agar kita dapat membuat helper:
Beberapa contoh:
Nikmati dengan JS!
UPD: Jack Allan diberikan solusi yang sedikit lebih baik sebenarnya. GJ Jack!
sumber
SomeFuncName
alih-aliharguments.callee
(keduanya menunjuk ke objek fungsi itu sendiri).Apa pun solusinya, itu tidak boleh rusak pada fungsi aneh, yang
toString()
tampak sama anehnya:Juga, mengapa menggunakan ekspresi reguler yang kompleks? Ini bisa dilakukan seperti:
Ini bekerja di mana-mana dengan setiap fungsi, dan satu-satunya regex adalah penghapusan spasi putih yang bahkan tidak memproses seluruh string karena
.split
triknya.sumber
Ok jadi pertanyaan lama dengan banyak jawaban yang memadai. di sini adalah penawaran saya yang tidak menggunakan regex, kecuali untuk tugas kasar stripping spasi putih. (Saya harus mencatat bahwa fungsi "strips_comments" sebenarnya menghapusnya, daripada menghapusnya secara fisik. Itu karena saya menggunakannya di tempat lain dan karena berbagai alasan memerlukan lokasi token non komentar asli untuk tetap utuh)
Ini adalah blok kode yang cukup panjang karena pasta ini termasuk kerangka uji mini.
sumber
Ini salah satu caranya:
Catatan: Ini hanya berfungsi pada browser yang mendukung
arguments.callee
.sumber
Catatan: jika Anda ingin menggunakan destruksi parameter ES6 dengan solusi teratas tambahkan baris berikut.
sumber
parameter fungsi nilai string gambar secara dinamis dari JSON . Karena item.product_image2 adalah string URL, Anda harus memasukkannya ke dalam tanda kutip ketika Anda memanggil changeImage di dalam parameter.
My Function Onclick
Fungsi saya
sumber