Tutorial JavaScript: Fungsi tingkat tinggi

Minggu lalu, saya dengan santai membuang istilah "fungsi tingkat tinggi" ketika berbicara tentang memoization. Meskipun saya merasa nyaman untuk mengubah istilah seperti itu sekarang, saya tidak selalu tahu apa artinya. Minggu ini kita akan memeriksa apa itu fungsi tingkat tinggi, menunjukkan beberapa contoh umum, dan mempelajari cara membuat milik kita sendiri.

Pada intinya, fungsi tingkat tinggi hanyalah fungsi yang menerima fungsi sebagai argumen atau mengembalikan fungsi. Ini dimungkinkan dalam JavaScript berkat fungsi kelas satu, yang berarti bahwa fungsi dalam JavaScript dapat diteruskan seperti variabel lainnya. Meskipun ini terdengar sangat mudah, itu tidak cukup menunjukkan kekuatan yang Anda miliki dengan fungsi kelas satu.

Jika Anda menulis JavaScript, Anda mungkin telah menggunakan fungsi tingkat tinggi dan bahkan tidak menyadarinya. Jika Anda pernah mengganti sebuah forloop dengan metode array, Anda telah menggunakan fungsi tingkat tinggi. Jika Anda pernah menggunakan hasil panggilan AJAX (tanpa async/ await), Anda telah menggunakan fungsi tingkat tinggi (janji dan panggilan balik melibatkan fungsi tingkat tinggi). Jika Anda pernah menulis komponen React yang menampilkan daftar item, Anda telah menggunakan fungsi tingkat tinggi. Mari kita lihat contoh-contoh itu:

const item = ['a', 'b', 'c', 'd', 'e']

// Daripada ini untuk loop ....

untuk (let i = 0; i <items.length - 1; i ++) {

  console.log (item [i]);

}

// Kita bisa menggunakan forEach, fungsi tingkat tinggi

// (forEach mengambil fungsi sebagai argumen)

items.forEach ((item) => console.log (item));

// Panggilan balik atau janji, jika Anda membuat

// permintaan asinkron, Anda menggunakan

// fungsi tingkat tinggi

get ('// aws.random.cat/meow', (response) => {

  putImageOnScreen (response.file);

});

get ('// random.dog/woof.json').then((response) => {

  putImageOnScreen (response.file);

});

// Pada komponen React di bawah ini, map digunakan,

// yang merupakan fungsi tingkat tinggi

const myListComponent = (alat peraga) => {

  kembali (

   

          {props.items.map ((item) => {

            kembali (

  • {barang}
  • )

          })}

      );

    };

Itu adalah contoh fungsi tingkat tinggi yang menerima fungsi sebagai argumen, tetapi banyak di antaranya juga mengembalikan fungsi. Jika Anda pernah melihat panggilan fungsi yang memiliki dua set tanda kurung, itu adalah fungsi tingkat tinggi. Hal semacam ini dulunya kurang umum, tetapi jika Anda bekerja dengan Redux sama sekali, Anda mungkin telah menggunakan connectfungsi tersebut, yang merupakan fungsi tingkat tinggi:

ekspor koneksi default (mapStateToProps, mapDispatchToProps) (MyComponent);

Dalam kasus di atas, kita memanggil connectdengan dua argumen dan mengembalikan fungsi, yang segera kita panggil dengan satu argumen. Anda mungkin juga telah melihat (atau menulis) perpustakaan logging sederhana yang menggunakan fungsi sebagai nilai yang dikembalikan. Pada contoh di bawah ini, kami akan membuat logger yang mencatat konteksnya sebelum pesan:

const createLogger = (konteks) => {

  kembali (pesan) => {

    console.log (`$ {context}: $ {msg}`);

  }

};

const log = createLogger ('myFile');

log ('Pesan yang sangat penting');

// log out "myFile: A very important message"

Contoh di atas mulai mengilustrasikan beberapa kekuatan dari fungsi tingkat tinggi (lihat juga posting saya sebelumnya tentang memoization). Perhatikan bahwa createLoggermengambil argumen yang kita referensikan di badan fungsi yang kita kembalikan. Fungsi yang dikembalikan itu, yang kita tetapkan ke variabel log, masih dapat mengakses contextargumen karena berada dalam lingkup tempat fungsi itu didefinisikan.

Fakta menyenangkan: Referensi contextdimungkinkan dengan penutupan. Saya tidak akan menutup di sini karena mereka layak mendapatkan pos mereka sendiri, tetapi mereka dapat digunakan bersama dengan fungsi tingkat tinggi untuk beberapa efek yang sangat menarik.

Misalnya, menggunakan closure bersama dengan fungsi tingkat tinggi dulunya adalah satu-satunya cara agar kita bisa memiliki variabel "pribadi" atau tahan kerusakan di JavaScript:

biarkan protectedObject = (function () {

  biarkan myVar = 0;

  kembali {

    dapatkan: () => myVar,

    kenaikan: () => myVar ++,

  };

}) ();

protectedObject.get (); // mengembalikan 0

protectedObject.increment ();

protectedObject.get (); // mengembalikan 1

myVar = 42; // ups! Anda baru saja membuat variabel global

protectedObject.get (); // masih mengembalikan 1

Namun, jangan sampai terbawa suasana. Fungsi tingkat tinggi tidak membutuhkan sesuatu yang mewah seperti penutupan. Mereka hanyalah fungsi yang mengambil fungsi lain sebagai argumen atau yang mengembalikan fungsi. Titik. Jika Anda ingin lebih banyak contoh atau bacaan lebih lanjut, lihat bab tentang fungsi tingkat tinggi di "JavaScript yang Eloquent" oleh Marijn Haverbeke.

Ada pertanyaan atau komentar? Jangan ragu untuk menghubungi Twitter: @freethejazz.