Panduan JavaScript Bagian 4: Fitur

Hari ini kami menerbitkan bagian keempat dari terjemahan manual JavaScript, yang dikhususkan untuk fungsi.

β†’ Bagian 1: program pertama, fitur bahasa, standar
β†’ Bagian 2: gaya kode dan struktur program
β†’ Bagian 3: variabel, tipe data, ekspresi, objek
β†’ Bagian 4: fitur
β†’ Bagian 5: array dan loop
β†’ Bagian 6: pengecualian, titik koma, literal wildcard
β†’ Bagian 7: mode ketat, kata kunci ini, acara, modul, perhitungan matematis
β†’ Bagian 8: Tinjauan Umum Fitur ES6
β†’ Bagian 9: Gambaran Umum Standar ES7, ES8, dan ES9



Fungsi JavaScript


Mari kita bicara tentang fungsi-fungsi dalam JavaScript, melakukan tinjauan umum terhadap mereka dan mempertimbangkan detailnya, pengetahuan yang akan memungkinkan Anda untuk menggunakannya secara efektif.

Fungsi adalah blok kode independen yang, setelah dideklarasikan, dapat dipanggil sebanyak yang diperlukan. Suatu fungsi dapat, meskipun tidak perlu, menerima parameter. Fungsi mengembalikan nilai tunggal.

Fungsi dalam JavaScript adalah objek, atau lebih tepatnya, mereka adalah objek tipe Function . Perbedaan utama mereka dari objek biasa, memberi mereka kemampuan luar biasa yang mereka miliki, adalah bahwa fungsi dapat disebut.

Selain itu, fungsi-fungsi dalam JavaScript disebut β€œfungsi kelas satu” karena mereka dapat ditugaskan ke variabel, mereka dapat diteruskan ke fungsi lain sebagai argumen, dan mereka dapat dikembalikan dari fungsi lain.

Pertama, kami mempertimbangkan fitur bekerja dengan fungsi dan konstruksi sintaksis yang sesuai yang ada dalam bahasa sebelum munculnya standar ES6 dan masih relevan.

Seperti inilah deklarasi fungsi.

 function doSomething(foo) { // - } 

Saat ini, fungsi-fungsi ini disebut "normal", membedakannya dari fungsi "panah" yang muncul di ES6.

Anda dapat menetapkan fungsi ke variabel atau konstanta. Konstruksi semacam itu disebut ekspresi fungsi.

 const doSomething = function(foo) { // - } 

Anda mungkin memperhatikan bahwa dalam contoh di atas, fungsi tersebut ditetapkan ke konstanta, tetapi itu sendiri tidak memiliki nama. Fungsi semacam itu disebut anonim. Fungsi serupa dapat diberi nama. Dalam hal ini, kita berbicara tentang ekspresi fungsi bernama (name function expression).

 const doSomething = function doSomFn(foo) { // - } 

Penggunaan ekspresi tersebut meningkatkan kenyamanan debugging (dalam pesan kesalahan di mana jejak stack dilakukan, nama fungsi terlihat). Nama fungsi dalam ekspresi fungsional mungkin juga diperlukan agar fungsi tersebut dapat memanggil dirinya sendiri, yang sangat diperlukan untuk menerapkan algoritma rekursif.

Dalam standar ES6, fungsi panah telah muncul, yang terutama nyaman untuk digunakan dalam bentuk yang disebut "fungsi sebaris" - sebagai argumen yang diteruskan ke fungsi lain (panggilan balik).

 const doSomething = foo => { // - } 

Fungsi panah, selain fakta bahwa struktur yang digunakan untuk mendeklarasikannya, lebih kompak daripada menggunakan fungsi biasa, mereka berbeda dari mereka dalam beberapa fitur penting, yang akan kita bahas di bawah ini.

Parameter fungsi


Parameter adalah variabel yang ditetapkan pada tahap mendeklarasikan fungsi dan akan berisi nilai-nilai yang diteruskan (nilai-nilai ini disebut argumen). Fungsi dalam JavaScript mungkin tidak memiliki parameter, atau memiliki satu atau lebih parameter.

 const doSomething = () => { // - } const doSomethingElse = foo => { // - } const doSomethingElseAgain = (foo, bar) => { // - } 

Berikut adalah beberapa contoh fungsi panah.

Dimulai dengan standar ES6, fungsi dapat memiliki apa yang disebut β€œparameter default”.

 const doSomething = (foo = 1, bar = 'hey') => { // - } 

Mereka mewakili nilai standar yang ditetapkan oleh parameter fungsi jika, ketika dipanggil, nilai beberapa parameter tidak ditetapkan. Sebagai contoh, fungsi yang ditunjukkan di atas dapat dipanggil baik dengan memberikan semua parameter yang diterimanya dan dengan metode lain.

 doSomething(3) doSomething() 

Dalam ES8, menjadi mungkin untuk menempatkan koma setelah argumen terakhir dari suatu fungsi (ini disebut trailing koma). Fitur ini memungkinkan Anda meningkatkan kenyamanan mengedit kode saat menggunakan sistem kontrol versi selama pengembangan program. Detail tentang ini dapat ditemukan di sini dan di sini .

Argumen yang diteruskan ke fungsi dapat direpresentasikan sebagai array. Untuk menguraikan argumen ini, Anda dapat menggunakan operator yang terlihat seperti tiga titik (ini disebut "operator ekstensi" atau "operator penyebaran"). Ini tampilannya.

 const doSomething = (foo = 1, bar = 'hey') => { // - } const args = [2, 'ho!'] doSomething(...args) 

Jika fungsi perlu mengambil banyak parameter, mengingat urutan urutannya bisa sulit. Dalam kasus seperti itu, objek dengan parameter dan peluang untuk merusak objek ES6 digunakan.

 const doSomething = ({ foo = 1, bar = 'hey' }) => { // - console.log(foo) // 2 console.log(bar) // 'ho!' } const args = { foo: 2, bar: 'ho!' } doSomething(args) 

Teknik ini memungkinkan, menggambarkan parameter dalam bentuk properti objek dan meneruskan fungsi ke objek, untuk mendapatkan akses fungsi ke parameter dengan nama mereka tanpa menggunakan konstruksi tambahan. Baca lebih lanjut tentang teknik ini di sini .

Nilai kembali dari fungsi


Semua fungsi mengembalikan nilai tertentu. Jika perintah kembali tidak ditentukan secara eksplisit, fungsi akan kembali undefined .

 const doSomething = (foo = 1, bar = 'hey') => { // - } console.log(doSomething()) 

Fungsi eksekusi berakhir baik setelah semua kode yang dikandungnya dieksekusi, atau setelah kata kunci return ditemui dalam kode. Ketika kata kunci ini ditemukan dalam suatu fungsi, operasinya selesai dan kontrol ditransfer ke tempat dari mana fungsi itu dipanggil.

Jika setelah kata kunci return Anda menentukan nilai tertentu, maka nilai ini kembali ke tempat pemanggilan fungsi sebagai hasil dari eksekusi fungsi ini.

 const doSomething = () => { return 'test' } const result = doSomething() // result === 'test' 

Hanya satu nilai yang dapat dikembalikan dari suatu fungsi. Agar dapat mengembalikan beberapa nilai, Anda bisa mengembalikannya baik sebagai objek menggunakan objek literal atau sebagai array, dan saat memanggil fungsi, gunakan konstruk penetapan destruktif. Nama parameter disimpan. Pada saat yang sama, jika Anda perlu bekerja dengan objek atau array yang dikembalikan dari suatu fungsi, yaitu dalam bentuk objek atau array, Anda bisa melakukannya tanpa tugas destruktif.

 const doSomething = () => { return ['Roger', 6] } const [ name, age ] = doSomething() console.log(name, age) //Roger 6 

Konstruksi const [ name, age ] = doSomething() dapat dibaca sebagai berikut: "mendeklarasikan konstanta name dan age dan menetapkan nilai-nilai elemen-elemen array yang akan dikembalikan fungsi."
Begini cara hal yang sama terlihat menggunakan objek.

 const doSomething = () => { return {name: 'Roger', age: 6} } const { name, age } = doSomething() console.log(name, age) //Roger 6 

Fungsi Bersarang


Fungsi dapat dideklarasikan di dalam fungsi lain.

 const doSomething = () => { const doSomethingElse = () => {} doSomethingElse() return 'test' } doSomething() 

Cakupan fungsi bersarang dibatasi oleh fungsi eksternal, tidak dapat dipanggil dari luar.

Metode Objek


Ketika fungsi digunakan sebagai properti objek, fungsi tersebut disebut metode objek.

 const car = { brand: 'Ford', model: 'Fiesta', start: function() {   console.log(`Started`) } } car.start() 

Kata kunci ini


Jika kita membandingkan tanda panah dan fungsi biasa yang digunakan sebagai metode objek, kita dapat menemukan perbedaan penting mereka, yang terdiri dari arti kata kunci this . Pertimbangkan sebuah contoh.

 const car = { brand: 'Ford', model: 'Fiesta', start: function() {   console.log(`Started ${this.brand} ${this.model}`) }, stop: () => {   console.log(`Stopped ${this.brand} ${this.model}`) } } car.start() //Started Ford Fiesta car.stop() //Stopped undefined undefined 

Seperti yang Anda lihat, memanggil metode start() mengarah ke hasil yang diharapkan, tetapi metode stop() jelas tidak bekerja dengan benar.

Ini disebabkan oleh fakta bahwa kata kunci ini berperilaku berbeda ketika digunakan dalam fungsi panah dan biasa. Yaitu, this dalam fungsi panah berisi tautan ke konteks yang mencakup fungsi tersebut. Dalam hal ini, ketika datang ke browser, konteks ini adalah objek window .

Begini cara eksekusi kode tersebut di konsol browser.

 const test = { fn: function() {   console.log(this) }, arrFn: () => {   console.log(this) } } test.fn() test.arrFn() 


Fitur Kata Kunci Ini dalam Fungsi Konvensional dan Panah

Seperti yang Anda lihat, memanggil ini dalam fungsi biasa berarti memanggil objek, dan this dalam fungsi panah menunjuk ke window .

Semua ini berarti bahwa fungsi panah tidak cocok untuk peran objek dan metode konstruktor (jika Anda mencoba menggunakan fungsi panah sebagai konstruktor, TypeError akan TypeError ).

Ekspresi Fungsional Dipanggil Segera


Ekspresi Fungsi yang Segera Diminta (IIFE) adalah fungsi yang secara otomatis dipanggil segera setelah dinyatakan.

 ;(function () { console.log('executed') })() 

Tanda titik koma sebelum IIFE adalah opsional, tetapi penggunaannya memungkinkan Anda untuk memastikan terhadap kesalahan yang terkait dengan penempatan titik koma otomatis.

Pada contoh di atas, kata yang executed akan masuk ke konsol, setelah itu IIFE akan keluar. IIFE, sama seperti fungsi lainnya, dapat mengembalikan hasil pekerjaan mereka.

 const something = (function () { return 'IIFE' })() console.log(something) 

Setelah menjalankan contoh sederhana ini, konsol akan mendapatkan garis IIFE , yang ternyata menjadi something setelah mengeksekusi ekspresi fungsi yang langsung disebut. Tampaknya tidak ada manfaat khusus dari desain seperti itu. Namun, jika dalam IIFE beberapa perhitungan rumit dilakukan yang perlu dilakukan hanya sekali, setelah itu mekanisme yang sesuai tidak diperlukan - kegunaan IIFE jelas. Yaitu, dengan pendekatan ini, setelah IIFE dieksekusi, hanya hasil yang dikembalikan oleh fungsi yang akan tersedia dalam program. Selain itu, kita dapat mengingat bahwa fungsi dapat mengembalikan fungsi dan objek lainnya. Kita berbicara tentang penutupan, kita akan membicarakannya di bawah.

Peningkatan Fitur


Sebelum kode JavaScript dijalankan, kode ini ditata ulang. Kita sudah bicara tentang mekanisme pengangkat variabel yang dideklarasikan menggunakan kata kunci var . Mekanisme serupa bekerja dengan fungsi. Yaitu, kita berbicara tentang fakta bahwa deklarasi fungsi dalam proses pemrosesan kode sebelum eksekusi dipindahkan ke bagian atas dari ruang lingkup mereka. Sebagai hasilnya, misalnya, ternyata Anda dapat memanggil fungsi sebelum dideklarasikan.

 doSomething() //did something function doSomething() { console.log('did something') } 

Jika Anda memindahkan panggilan fungsi sehingga berjalan setelah deklarasi, tidak ada yang akan berubah.

Jika, dalam situasi yang sama, ekspresi fungsional digunakan, maka kode yang sama akan menimbulkan kesalahan.

 doSomething() //TypeError var doSomething = function () { console.log('did something') } 

Dalam kasus ini, ternyata meskipun deklarasi variabel doSomething naik ke bagian atas ruang lingkup, ini tidak berlaku untuk operasi penugasan.
Jika, alih-alih var , Anda menggunakan kata kunci let atau const dalam situasi yang sama, kode ini juga tidak akan berfungsi, namun, sistem akan menampilkan pesan kesalahan yang berbeda ( ReferenceError daripada TypeError ), karena ketika menggunakan let dan const , deklarasi variabel dan konstan tidak dinaikkan.

Fungsi panah


Sekarang kita akan berbicara lebih banyak tentang fungsi panah yang sudah kita temui. Mereka dapat dianggap sebagai salah satu inovasi paling signifikan dari standar ES6, mereka berbeda dari fungsi biasa tidak hanya dalam penampilan, tetapi juga dalam perilaku mereka. Hari-hari ini mereka digunakan sangat luas. Mungkin tidak ada proyek modern tunggal di mana mereka tidak akan digunakan dalam sebagian besar kasus. Kita dapat mengatakan bahwa penampilan mereka selamanya mengubah penampilan kode JS dan fitur kerjanya.

Dari sudut pandang murni eksternal, sintaks untuk mendeklarasikan fungsi panah lebih kompak daripada sintaks fungsi biasa. Berikut adalah deklarasi fungsi reguler.

 const myFunction = function () { //... } 

Berikut adalah pengumuman fungsi panah, yang, secara umum, jika Anda tidak mempertimbangkan fitur fungsi panah, mirip dengan yang sebelumnya.

 const myFunction = () => { //... } 

Jika isi fungsi panah hanya berisi satu perintah, yang hasilnya mengembalikan fungsi ini, ia dapat ditulis tanpa tanda kurung dan tanpa kata kunci return . Misalnya, fungsi seperti itu mengembalikan jumlah argumen yang diteruskan ke sana.

 const myFunction = (a,b) => a + b console.log(myFunction(1,2)) //3 

Seperti yang Anda lihat, parameter fungsi panah, seperti dalam kasus dengan fungsi biasa, dijelaskan dalam tanda kurung. Selain itu, jika fungsi seperti itu hanya membutuhkan satu parameter, ia dapat ditentukan tanpa tanda kurung. Sebagai contoh, berikut adalah fungsi yang mengembalikan hasil pembagian angka yang diteruskan oleh 2.

 const myFunction = a => a / 2 console.log(myFunction(8)) //4 

Akibatnya, ternyata fungsi panah sangat nyaman digunakan dalam situasi di mana fungsi kecil diperlukan.

▍ Pengembalian hasil fungsi secara implisit


Kami telah menyentuh fitur fungsi panah ini, tetapi sangat penting untuk membahasnya secara lebih rinci. Kita berbicara tentang fakta bahwa fungsi panah satu baris mendukung pengembalian implisit hasil pekerjaan mereka. Contoh mengembalikan nilai primitif dari fungsi panah satu baris yang telah kita lihat. Bagaimana jika fungsi seperti itu harus mengembalikan objek? Dalam hal ini, kurung kurawal dari objek literal dapat membingungkan sistem, sehingga tanda kurung digunakan dalam tubuh fungsi.

 const myFunction = () => ({value: 'test'}) const obj = myFunction() console.log(obj.value) //test 

▍ Kata kunci ini dan fungsi panah


Di atas, ketika kami melihat fitur this , kami membandingkan fungsi reguler dan panah. Bagian ini dimaksudkan untuk menarik perhatian Anda pada pentingnya perbedaan mereka. Kata this , dengan sendirinya, dapat menyebabkan kesulitan tertentu, karena tergantung pada konteks eksekusi kode dan pada apakah mode ketat diaktifkan atau tidak.

Seperti yang telah kita lihat, ketika menggunakan this dalam metode objek yang diwakili oleh fungsi biasa, this menunjuk ke objek yang dimiliki metode tersebut. Dalam hal ini, kita berbicara tentang mengikat kata kunci this ke nilai yang mewakili konteks fungsi. Secara khusus, jika suatu fungsi disebut sebagai metode objek, maka kata kunci ini terikat ke objek ini.

Dalam kasus fungsi panah, ternyata pengikatan ini tidak dilakukan di dalamnya, mereka menggunakan this dari ruang lingkup mereka. Akibatnya, mereka tidak direkomendasikan untuk digunakan sebagai metode objek.

Masalah yang sama terjadi ketika menggunakan fungsi sebagai pengendali event untuk elemen DOM. Misalnya, button elemen HTML digunakan untuk menggambarkan tombol. Acara click ketika pengguna mengklik tombol. Untuk merespons peristiwa ini dalam kode, Anda harus terlebih dahulu mendapatkan tautan ke elemen yang sesuai, dan kemudian menetapkannya sebagai pengendali acara click sebagai fungsi. Dengan demikian, Anda dapat menggunakan fungsi biasa dan fungsi panah. Tetapi, jika dalam event handler Anda perlu mengakses elemen yang dipanggil (yaitu, untuk this ), fungsi panah tidak akan bekerja di sini, karena nilai this tersedia di dalamnya menunjuk ke objek window . Untuk menguji ini dalam praktiknya, buat halaman HTML, kode yang ditunjukkan di bawah ini, dan klik tombol.

 <!DOCTYPE html> <html> <body>   <button id="fn">Function</button>   <button id="arrowFn">Arrow function</button>   <script>     const f = document.getElementById("fn")     f.addEventListener('click', function () {         alert(this === f)     })     const af = document.getElementById("arrowFn")     af.addEventListener('click', () => {         alert(this === window)     })   </script> </body> </html> 

Dalam hal ini, ketika Anda mengklik tombol-tombol ini, jendela yang berisi true akan muncul. Namun, dalam pengendali event click tombol dengan pengenal fn , persamaan this tombol diperiksa, dan pada tombol dengan pengenal arrowFn , kesetaraan this dan objek window diperiksa.

Akibatnya, jika Anda perlu menyebutnya dalam event handler dari elemen HTML, fungsi panah tidak akan berfungsi untuk desain handler tersebut.

Sirkuit pendek


Penutupan adalah konsep penting dalam JavaScript. Bahkan, jika Anda menulis fungsi JS, maka Anda juga menggunakan penutupan. Penutupan digunakan dalam beberapa pola desain - jika Anda perlu mengatur kontrol ketat terhadap akses ke data atau fungsi tertentu.

Ketika suatu fungsi dipanggil, ia memiliki akses ke segala sesuatu yang ada di dalam lingkup eksternal. Tetapi tidak ada akses ke apa yang dinyatakan di dalam fungsi. Yaitu, jika suatu variabel (atau fungsi lain) dideklarasikan dalam suatu fungsi, mereka tidak dapat diakses oleh kode eksternal baik selama eksekusi fungsi atau setelah selesainya pekerjaannya. Namun, jika fungsi lain dikembalikan dari fungsi, maka fungsi baru ini akan memiliki akses ke semua yang dideklarasikan dalam fungsi asli. Dalam hal ini, semua ini akan disembunyikan dari kode eksternal pada penutupan.

Pertimbangkan sebuah contoh. Berikut adalah fungsi yang mengambil nama anjing, dan kemudian menampilkannya di konsol.

 const bark = dog => { const say = `${dog} barked!` ;(() => console.log(say))() } bark(`Roger`) // Roger barked! 

Nilai yang dikembalikan oleh fungsi ini belum menarik bagi kami, teks ditampilkan di konsol menggunakan IIFE, yang dalam hal ini tidak memainkan peran khusus, namun, ini akan membantu kami melihat hubungan antara fungsi ini dan variannya, di mana, alih-alih memanggil fungsi yang menampilkan teks ke konsol, kami akan mengembalikan fungsi ini dari fungsi bark() ditulis ulang bark() .

 const prepareBark = dog => { const say = `${dog} barked!` return () => console.log(say) } const bark = prepareBark(`Roger`) bark() // Roger barked! 

Hasil kode dalam dua kasus adalah sama. Tetapi dalam kasus kedua, apa yang ditransfer ke fungsi asli ketika dipanggil (nama anjing, Roger ) disimpan dalam penutupan, setelah itu digunakan oleh fungsi lain yang dikembalikan dari aslinya.

Mari kita lakukan percobaan lain - membuat, menggunakan fungsi asli, dua yang baru untuk anjing yang berbeda.

 const prepareBark = dog => { const say = `${dog} barked!` return () => {   console.log(say) } } const rogerBark = prepareBark(`Roger`) const sydBark = prepareBark(`Syd`) rogerBark() sydBark() 

Kode ini akan menampilkan yang berikut ini.

 Roger barked! Syd barked! 

Ternyata nilai konstanta say terkait dengan fungsi yang dikembalikan dari fungsi prepareBark() .

Perhatikan bahwa say , saat Anda memanggil prepareBark() lagi, ia mendapat nilai baru, sedangkan nilai yang tercatat say prepareBark() dipanggil tidak berubah. Intinya adalah bahwa dengan setiap panggilan ke fungsi ini, penutupan baru dibuat.

Ringkasan


Hari ini kita berbicara tentang fungsi panah dan umum, tentang fitur deklarasi dan penggunaannya, tentang bagaimana kata kunci this berperilaku dalam situasi yang berbeda, dan tentang penutupan. Lain kali kita membahas array dan loop.

Pembaca yang budiman! Bagaimana perasaan Anda tentang fungsi panah di JavaScript?

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


All Articles