mata utama
Tujuan rekursi
rekursi adalah teknik yang meleleh melalui operasi dengan mempunyai fungsi panggilan sendiri berulang kali sehingga hasilnya diperolehi. Kebanyakan gelung boleh ditulis semula dalam gaya rekursif, dan dalam beberapa bahasa pengaturcaraan berfungsi, kaedah gelung ini adalah lalai.
rekursi lebih baik digunakan apabila anda perlu berulang kali memanggil fungsi yang sama dengan parameter yang berbeza dalam gelung. Walaupun ia boleh digunakan dalam banyak kes, ia adalah yang paling berkesan dalam menyelesaikan masalah yang melibatkan cawangan berulang seperti matematik fraktal, menyusun atau melintasi nod struktur data kompleks atau tidak linear.
Salah satu sebab mengapa rekursi disukai dalam bahasa pengaturcaraan berfungsi ialah ia membolehkan kod bangunan yang tidak memerlukan penggunaan pembolehubah tempatan untuk menetapkan dan mengekalkan keadaan. Fungsi rekursif juga mudah diuji kerana mereka mudah ditulis dengan cara yang murni, mempunyai nilai pulangan yang spesifik dan konsisten untuk sebarang input yang diberikan dan tidak mempunyai kesan sampingan pada keadaan pemboleh ubah luaran.
Cycle
Contoh fungsi klasik yang rekursi boleh digunakan adalah faktorial. Ini adalah fungsi yang mengembalikan hasil nombor berulang kali didarabkan oleh setiap integer sebelumnya, sepanjang jalan ke 1.
Contohnya, faktorial 3 ialah:Faktorial
6 adalah:
<code>3 × 2 × 1 = 6</code>
Anda dapat melihat seberapa cepat hasil ini semakin besar. Anda juga boleh melihat kami mengulangi tingkah laku yang sama berulang kali. Kami mengambil hasil operasi pendaraban dan membiaknya dengan nilai kedua kepada tolak 1. Kemudian kita melakukan ini lagi dan lagi sehingga kita mencapai 1.
menggunakan gelung untuk, tidak sukar untuk membuat fungsi yang berulang untuk melakukan ini sehingga hasil yang betul dikembalikan:
<code>6 × 5 × 4 × 3 × 2 × 1 = 720</code>
Ini berfungsi, tetapi dari sudut pandangan pengaturcaraan berfungsi, ia tidak elegan. Untuk menyokong gelung untuk dan kemudian mengembalikan hasilnya, kami perlu menggunakan beberapa pembolehubah tempatan yang mengekalkan dan menjejaki negeri. Bukankah lebih ringkas jika kita boleh membuang gelung untuk dan mengamalkan kaedah JavaScript yang lebih berfungsi?
rekursi
kita tahu bahawa JavaScript membolehkan kita menulis fungsi yang mengambil fungsi sebagai parameter. Jadi bagaimana jika kita mahu menggunakan fungsi sebenar kita menulis dan melaksanakannya dalam konteks di mana kita menjalankannya?
Adakah ini mungkin? Pasti! Sebagai contoh, pertimbangkan seperti gelung semasa:
var factor = function(number) { var result = 1; var count; for (count = number; count > 1; count--) { result *= count; } return result; }; console.log(factor(6)); // 720
Selepas ini dilakukan, nilai kaunter telah berubah, tetapi gelung telah menyelesaikan tugasnya mencetak setiap nilai, ketika kami perlahan -lahan mengekstrak negara daripadanya.
versi rekursif gelung yang sama mungkin kelihatan seperti ini:
var counter = 10; while(counter > 0) { console.log(counter--); }
Adakah anda melihat bagaimana kita memanggil fungsi undur secara langsung dalam definisi fungsi undur? JavaScript mengendalikannya seperti bos dan hanya melakukan apa yang anda mahu lakukan. Setiap undur masa dilaksanakan, trek JavaScript di mana ia dipanggil, dan kemudian kembali ke timbunan fungsi panggilan sehingga selesai. Fungsi kami juga mengelakkan mengubah keadaan mana -mana pembolehubah, tetapi masih menggunakan nilai yang diluluskan untuk mengawal rekursi.
Kembali ke kes faktorial kami, kami boleh menulis semula fungsi sebelumnya seperti ini untuk menggunakan rekursi:
var countdown = function(value) { if (value > 0) { console.log(value); return countdown(value - 1); } else { return value; } }; countdown(10);
Kod penulisan dengan cara ini membolehkan kita menerangkan keseluruhan proses dengan cara tanpa statistik tanpa sebarang kesan sampingan. Ia juga perlu diperhatikan bahawa kita mula -mula menguji nilai parameter yang diluluskan kepada fungsi dan kemudian melakukan apa -apa pengiraan. Kami mahu apa -apa fungsi yang akan memanggil dirinya untuk keluar dengan cepat dan bersih apabila ia mencapai penamatannya. Untuk faktorial yang dikira dengan cara ini, apabila nombor masuk adalah sifar atau negatif, keadaan penamatan dicapai (kita juga boleh menguji nilai negatif dan mengembalikan mesej yang berbeza jika kita mahu).
pengoptimuman panggilan ekor
Salah satu masalah dengan pelaksanaan JavaScript kontemporari adalah bahawa mereka tidak mempunyai cara standard untuk mencegah fungsi rekursif daripada menyusun ingatan diri mereka yang tak terhingga dan memakan sehingga mereka melebihi kapasiti enjin. Fungsi rekursif JavaScript perlu menjejaki tempat mereka dipanggil dari setiap masa supaya mereka dapat terus melaksanakan di tempat yang betul.
Dalam banyak bahasa pengaturcaraan berfungsi seperti Haskell dan Skim, ini diuruskan menggunakan teknik yang dipanggil Pengoptimuman Call Tail. Menggunakan pengoptimuman panggilan ekor, setiap gelung berterusan dalam fungsi rekursif akan berlaku dengan serta -merta, dan bukannya menumpuk dalam ingatan.
Dalam teori, pengoptimuman panggilan ekor adalah sebahagian daripada standard ECMAScript 6 (versi seterusnya JavaScript semasa), tetapi kebanyakan platform belum melaksanakannya sepenuhnya.
Fungsi Bounce
Jika perlu, ada cara untuk memaksa JavaScript untuk melaksanakan fungsi rekursif dengan cara yang selamat. Sebagai contoh, fungsi lantunan tersuai boleh dibina untuk mengurus pelaksanaan rekursif secara beransur -ansur, meninggalkan hanya satu operasi pada timbunan pada satu masa. Fungsi lantunan yang digunakan dengan cara ini dapat memanfaatkan keupayaan JavaScript untuk mengikat fungsi ke konteks tertentu untuk melantun fungsi rekursif kembali kepada dirinya sendiri, membina hasil satu demi satu sehingga gelung selesai. Ini akan mengelakkan membuat operasi timbunan yang mendalam menunggu pelaksanaan.
Malah, menggunakan fungsi melantun sering mengurangkan prestasi untuk keselamatan. Selain itu, kebanyakan keanggunan dan kebolehbacaan yang kita dapat dengan menulis fungsi secara rekursif hilang dalam konvolusi kod yang diperlukan untuk membuat pendekatan ini berfungsi di JavaScript.
Jika anda ingin tahu, saya menggalakkan anda membaca lebih lanjut mengenai konsep ini dan berkongsi pendapat anda dalam perbincangan di bawah. Anda boleh memulakan dengan topik pendek di StackOverflow dan meneroka beberapa artikel oleh Don Taylor dan Mark McDonnell yang lebih mendalam ke dalam kebaikan dan keburukan fungsi memantul dalam JavaScript.
kita belum pada ketika itu
rekursi adalah teknik yang kuat yang bernilai mengetahui. Dalam banyak kes, rekursi adalah cara yang paling mudah untuk menyelesaikan masalah yang rumit. Walau bagaimanapun, sebelum ECMAScript 6 melaksanakan sepenuhnya dengan pengoptimuman panggilan ekor di mana kita memerlukannya, kita perlu berhati -hati tentang bagaimana dan di mana rekursif digunakan.
Soalan Lazim Mengenai Rekursi dalam JavaScript berfungsi (Soalan Lazim)
Keadaan asas dalam rekursi adalah keadaan yang menghalang fungsi daripada memanggil dirinya tak terhingga. Ia adalah penting kerana tanpa itu, fungsi rekursif akan memanggil dirinya secara tak terhingga, menyebabkan kesilapan limpahan timbunan. Keadaan asas biasanya adalah syarat bahawa fungsi memeriksa sebelum membuat panggilan rekursif. Jika keadaan ini dipenuhi, fungsi ini mengembalikan nilai dan berhenti memanggilnya sendiri.
Dalam JavaScript, rekursi berfungsi dengan memanggil fungsi itu sendiri sehingga keadaan asas dicapai. Fungsi ini dibahagikan kepada kes asas dan kes rekursif. Kes asas mengembalikan nilai tanpa memanggil fungsi itu lagi, sementara kes rekursif memanggil fungsi itu lagi dengan parameter yang berbeza. Fungsi ini terus memanggil sendiri sehingga kes asas dicapai, di mana ia mula mengembalikan nilai.
rekursi ekor adalah jenis rekursi khas, di mana panggilan rekursif adalah operasi terakhir dalam fungsi. Ini penting kerana ia membolehkan pengoptimuman enjin JavaScript untuk berulang, menggunakan teknik yang dipanggil pengoptimuman panggilan ekor. Ini dapat mengurangkan jumlah memori yang digunakan oleh fungsi, yang membolehkannya mengendalikan input yang lebih besar.
rekursi boleh menjadikan kod lebih ringkas dan mudah difahami dengan memecahkan masalah yang kompleks ke dalam masalah yang lebih mudah. Ia amat berguna untuk tugas -tugas seperti melintasi struktur data pokok. Walau bagaimanapun, rekursi juga mungkin kurang cekap daripada penyelesaian berulang, dan jika dilaksanakan dengan tidak betul, ia boleh menyebabkan ralat limpahan timbunan.
Apabila fungsi rekursif memanggil dirinya terlalu banyak dan mengisi timbunan panggilan, ralat limpahan timbunan akan berlaku. Untuk mengelakkan ini, pastikan fungsi rekursif anda mempunyai kes asas yang akhirnya akan dicapai. Juga, pertimbangkan untuk menggunakan rekursi ekor, yang enjin JavaScript boleh mengoptimumkan untuk menggunakan memori yang kurang.
Dalam pengaturcaraan berfungsi, rekursi sering digunakan sebagai pengganti gelung. Oleh kerana pengaturcaraan berfungsi tidak menggalakkan penggunaan keadaan berubah -ubah, rekursi boleh digunakan untuk melakukan operasi berulang tanpa mengubah mana -mana negeri.
Ya, dalam teori, semua fungsi rekursif boleh ditukar menjadi fungsi berulang. Walau bagaimanapun, versi berulang boleh menjadi lebih kompleks dan sukar difahami, terutamanya untuk fungsi yang melibatkan traversals pokok atau graf kompleks.
rekursi bersama merujuk kepada dua atau lebih fungsi yang dipanggil antara satu sama lain dalam gelung. Ini mungkin teknik yang kuat untuk menyelesaikan beberapa jenis masalah, tetapi mungkin juga lebih sukar untuk difahami dan debug daripada rekursi mudah.
Menghancurkan fungsi rekursif boleh mencabar kerana panggilan fungsi berulang. Walau bagaimanapun, ia mungkin membantu mencetak parameter fungsi dan mengembalikan nilai pada setiap langkah menggunakan pernyataan Console.log. Di samping itu, sangat berguna untuk menggunakan alat debugger yang membolehkan anda melakukan fungsi panggilan langkah demi langkah.
Ya, fungsi rekursif mungkin tidak begitu efisien sebagai rakan berulangnya kerana overhead panggilan fungsi berulang. Sekiranya mereka memanggil diri mereka terlalu banyak, mereka juga boleh menyebabkan kesilapan limpahan timbunan. Walau bagaimanapun, dalam banyak kes, kebolehbacaan dan kesederhanaan penyelesaian rekursif boleh melebihi pertimbangan prestasi ini.
Atas ialah kandungan terperinci Rekursi dalam javascript berfungsi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!