Keindahan fungsi TIDAK-anonim dalam JavaScript

gambar


Menurut beberapa jajak pendapat , fungsi panah anonim dalam JavaScript adalah fitur paling populer dari ES-2015, yang juga digarisbawahi oleh banyaknya tutorial di Internet. Mereka jelas sangat berguna, tetapi dalam artikel singkat ini kita akan melihat contoh-contoh penggunaan kehilangan perhatian, paling tidak ekspresi indah dengan fungsi bernama - NFE.


Bantuan singkat


Named Function Expression - ekstensi ekspresi fungsional dalam JavaScript yang memungkinkan Anda memberi nama fungsi yang dibuat sebagai bagian dari ekspresi ( FunctionExpression ):


let fe = function named(...) { /* function body */ }; 

Intinya adalah bahwa di dalam fungsi yang dirujuk oleh variabel fe , ada akses ke fungsi itu sendiri melalui nama yang disebut . Tidak mungkin untuk menulis ulang nama hanya dari dalam fungsi!


Bagaimana cara menggunakannya


Sebagai contoh, kita perlu menulis fungsi dekorasi yang akan menghitung jumlah panggilan ke beberapa fungsi. Ini dapat dilakukan dengan cukup elegan dengan NFE:


 const count = f => function df() { df.calls = (df.calls || 0) + 1; return f(...arguments); }; 

Di sini kami mendapat akses ke fungsi df yang dikembalikan, sehingga ketika dipanggil, kami menyimpan penghitung di properti panggilan , yang akan tersedia untuk dibaca jika perlu:


 const csum = count((x, y) => x + y); csum(5, 10); // 15 csum(50, 1); // 51 csum.calls; // 2 

Atau simpan semua hasil pemanggilan fungsi:


 const accum = f => function df() { let res = f(...arguments); (df.results = (df.results || [])).push(res); return res; }; 

Dalam hal apa pun, kami memanfaatkan fakta bahwa fungsi dalam JavaScript adalah objek, dan kami dapat menambahkannya dengan properti yang diperlukan dalam tugas lokal kami.


Jelas, kita bisa memanggil fungsi. Menggunakan NFE untuk rekursi sangat bagus. Misalkan kita ingin menemukan anggota ke-urutan Fibonacci (untuk beberapa alasan, semua orang menginginkan ini cepat atau lambat):


 const rf = function getfn(n) { return n > 2 ? getfn(n - 2) + getfn(n - 1) : 1; }; rf(1); // 1 rf(10); // 55 

Tidak ada gunanya memperhatikan "tailing" di sini. Tetapi pada kemampuan untuk melakukan hal yang sama melalui FunctionDeclaration - ya. Tetapi fungsi ekspresi memiliki satu keuntungan: jika Anda ingin mentransfer fungsi dari rf ke variabel lain, Anda tidak perlu mengedit panggilan rekursif di dalamnya.


Contoh penerapan timer yang rapi:


 const ping = (callback, t) => setTimeout(function pf() { callback(); setTimeout(pf, t); }, t); 

Di sini kita menggunakan NFE sebagai literal sebagai argumen alih-alih mendeklarasikan variabel yang tidak perlu. Kenapa tidak setInterval ? Alih-alih panggilan balik, di sini mungkin ada menunggu untuk resolusi janji sebelum centang waktu berikutnya.


Contoh yang menarik adalah kombinasi NFE dan IIFE ( Ekspresi Fungsi Segera-Dibawa ), ketika di tempat hanya hasil dari fungsi rekursif yang diperlukan. Sekali saja:


 let data = { f10: function fact(n) { return n > 1 ? n * fact(n - 1) : 1; }(10) }; data.f10; // 3628800 

Benarkah begitu? yah, inilah masalah sebenarnya: Ada beberapa fungsi f yang meningkat secara ketat yang bekerja dalam himpunan bilangan asli. Temukan titik ekstrim x di mana nilai fungsi tidak melebihi y yang diberikan. Contoh dari fungsi seperti itu adalah f(x) = 3 * x + 5 atau f(x) = 2^x + 11 .


 const find = (f, y) => function bs(a, b) { if (a + 1 === b) return a; let m = Math.ceil((a + b) / 2); return f(m) <= y ? bs(m, b) : bs(a, m); }(-1, y + 1); find(x => 3 * x + 5, 200); // 65 find(x => Math.pow(2, x) + 11, 1000); // 9 

Kami tidak akan membahas detail matematika. Pertimbangkan implementasinya:


  1. Fungsi find yang diperlukan memiliki dua parameter kami f, y dan mengembalikan hasil IIFE.
  2. Fungsi yang dipanggil secara instan mengimplementasikan pencarian biner untuk suatu solusi, panggilan pertama mendapatkan rentang awal.
  3. Pencarian itu sendiri dilaksanakan melalui rekursi, yang menggunakan nama NFE untuk panggilan berikutnya. Kami tidak mendeklarasikan fungsi pencarian dan tidak membuat variabel baru.

Tentu saja, masalah yang sama dapat diselesaikan melalui siklus sederhana dengan prasyarat, tetapi ini terlalu penting untuk pengkodean konsol.


Akhirnya, beberapa kata tentang jejak tumpukan. Kami memiliki beberapa fungsi NFE, di mana pengecualian dilemparkan:


 const fe = function named() { throw new Error('Something went wrong'); }; 

Karena kita memiliki fungsi bernama dalam ekspresi, kita akan melihatnya di jejak tumpukan:


 Uncaught Error: Something went wrong at named (<anonymous>:2:11) 

Namun, mulai ES-2015, banyak ekspresi fungsi anonim sebenarnya membuat fungsi dengan nama, mengeluarkannya di luar konteks:


 const unnamed = function() { throw new Error('Something went wrong'); }; 

Fungsi di sisi kanan ekspresi dikaitkan dengan variabel di sebelah kiri:


 Uncaught Error: Something went wrong at unnamed (<anonymous>:2:7) 

Tetapi ini tidak selalu memungkinkan. Contoh klasik adalah inisialisasi skrip perpustakaan eksternal melalui IIFE, sebagai opsi:


 /** * @license * @description */ ;(function() { // some awesome code }.call(this)); 

Atau contoh yang sering dari fungsi yang mengembalikan fungsi lain:


 const bind = (f, ctx) => function() { return f.apply(ctx, arguments); }; 

Tidak ada variabel untuk output, jadi dalam kasus pengecualian kita akan melihat anonim . NFE dapat membantu sedikit dalam proses pengadilan.


Kesimpulan singkat


NFE pandai menulis kode ringkas dan tidak didukung untuk dengan cepat membuat prototipe berbagai tugas. Untuk menggunakan kecantikan mereka dalam kode akhir, Anda harus berpikir beberapa kali: JavaScript sudah kelebihan beban dengan spesifikasi menarik.

Source: https://habr.com/ru/post/id427461/


All Articles