Sintaks sama, dua tugas
Tiga titik ... muncul di banyak kode JavaScript modern, dan melakukan dua hal yang berlawanan tergantung tempatnya muncul. Begitu kamu melihat polanya, setiap pemakaian ... masuk ke salah satu dari dua kelompok:
- Rest:
...namedi sisi penerima mengumpulkan beberapa nilai ke dalam satu array atau object. - Spread:
...valuedi sisi pemberi membentangkan array atau object menjadi bagian-bagiannya.
Itulah seluruh cara memikirkannya. Sisa halaman ini hanyalah contoh masing-masing, dan pola yang akan terus kamu pakai.
Rest parameter: mengumpulkan argumen
Rest parameter di definisi fungsi mengumpulkan argumen berapa pun banyaknya ke dalam array sungguhan:
nums adalah array biasa. Kamu bisa memakai .map padanya, .filter, mengecek .length-nya, mengirimnya ke fungsi lain, semua yang bisa dilakukan array.
Rest parameter bisa dicampur dengan parameter biasa, tapi rest parameter harus ditulis paling akhir:
label mengambil argumen pertama; semua sesudahnya masuk ke items. Menulis rest parameter di mana pun selain paling akhir adalah syntax error.
Rest vs. object arguments versi lama
Kode JavaScript lama memakai variabel ajaib bernama arguments di dalam fungsi biasa. Bentuknya mirip array tapi bukan array, artinya method array tidak bisa langsung dipakai padanya. Rest parameter menggantikannya dengan rapi:
Arrow function bahkan tidak punya object arguments, jadi rest parameter adalah satu-satunya cara menerima argumen dengan jumlah bervariasi di arrow function. Utamakan ...args di kode baru mana pun.
Spread pada pemanggilan fungsi
Spread melakukan kebalikannya: ia mengambil array lalu membongkarnya menjadi argumen-argumen terpisah di tempat pemanggilan.
Math.max menerima angka satu per satu, bukan array. Sebelum ada spread, kamu harus menulis Math.max.apply(null, nums). Sekarang cukup ... dan selesai.
Perhatikan bahwa ... yang persis sama adalah rest di definisi fungsi dan spread di pemanggilan fungsi: posisinya yang memberi tahu mana yang mana.
Spread pada array literal
Spread ke dalam array literal menyalin atau menggabungkan array:
[...a] memberimu array baru dengan elemen yang sama, berguna saat kamu ingin mengurutkan atau mengubah tanpa menyentuh aslinya:
scores tidak tersentuh karena .sort berjalan pada salinannya. Kebiasaan kecil, manfaat besar saat kamu menulis kode yang tidak boleh punya efek samping mengejutkan.
Spread pada object literal
Spread juga berfungsi pada object biasa, menggabungkan property-nya ke object baru:
Key yang belakangan yang menang. updates.age menimpa user.age, dan city ikut terbawa. Urutan spread menentukan hasilnya, jadi ingat ini saat kamu menumpuk default dan override:
Default lebih dulu, pilihan pengguna kemudian. Pengguna menang di fontSize, dan mewarisi theme.
Jebakan shallow copy
Spread menyalin sedalam satu tingkat. Object dan array bersarang tetap dipakai bersama oleh object asli dan salinannya:
Kedua array menampilkan tag baru karena copy.tags dan original.tags adalah array yang sama. Spread tidak meng-clone list bersarang itu; ia hanya menyalin referensinya.
Untuk deep copy sungguhan dari data biasa, pakai structuredClone:
Sekarang kedua array tidak saling bergantung. structuredClone sudah tersedia di browser modern dan Node, menangani struktur bersarang, dan menjadi pilihan yang tepat setiap kali "dangkal" tidak cukup.
Rest pada destructuring
Rest juga berfungsi pada destructuring, tempat ia mengumpulkan elemen atau property yang tersisa:
Mengambil beberapa field lalu menyimpan sisanya dalam satu object adalah pola umum saat meneruskan props, membuang field sensitif, atau membuat versi data yang sudah diperbarui:
password diambil keluar (dan diabaikan); safe menyimpan semua sisanya. Tanpa mutasi, tanpa menyalin manual.
Ringkasan singkat
...namedi daftar parameter atau pola destructuring adalah rest: ia mengumpulkan....valuedi pemanggilan fungsi, array literal, atau object literal adalah spread: ia membentangkan.- Salinan hasil spread bersifat shallow. Struktur bersarang tetap dipakai bersama. Pakai
structuredCloneuntuk deep copy. - Rest parameter adalah array sungguhan; pakai ini sebagai pengganti
arguments. - Pada object literal, spread yang belakangan menimpa yang sebelumnya, dan begitulah cara membuat default ditambah override.
Berikutnya: closure
Fungsi di JavaScript tidak hanya menerima input dan mengembalikan output; ia juga mengingat scope tempat ia didefinisikan. Ingatan itu disebut closure, dan itulah mekanisme di balik callback, factory, dan sebagian besar pola yang akan kamu temui di halaman berikutnya.
Pertanyaan yang sering diajukan
Apa bedanya rest dan spread di JavaScript?
Keduanya memakai sintaks ... yang sama, tapi tugasnya berlawanan. Rest mengumpulkan beberapa nilai ke dalam satu array; ia muncul di daftar parameter fungsi dan destructuring. Spread membentangkan iterable atau object menjadi bagian-bagiannya; ia muncul di pemanggilan fungsi, array literal, dan object literal. Kalau ... ada di sisi penerima, itu rest; kalau ada di sisi pemberi, itu spread.
Bagaimana cara kerja rest parameter di sebuah fungsi?
Rest parameter seperti function sum(...nums) mengumpulkan setiap argumen yang dikirim ke fungsi ke dalam array sungguhan bernama nums. Ia harus menjadi parameter terakhir di daftar. Tidak seperti object arguments yang lebih lama, rest parameter adalah array sungguhan, jadi .map, .filter, dan .reduce bisa langsung dipakai padanya.
Apakah spread operator membuat deep copy?
Tidak. Spread hanya menyalin satu tingkat, yaitu shallow copy. { ...user } memberimu object baru dengan key tingkat atas yang sama, tapi object dan array bersarang di dalamnya tetap berupa referensi yang dipakai bersama. Untuk deep copy, pakai structuredClone(value) atau serialisasi lewat JSON untuk data biasa.