Daftar harga yang ditampilkan acak menyulitkan pembeli mencari yang termurah. Menata urutan adalah kebutuhan hampir semua daftar — harga dari kecil ke besar, nama sesuai abjad, atau urutan yang dibalik sepenuhnya. JavaScript menjawabnya dengan sort dan reverse, tetapi keduanya menyimpan dua kejutan yang perlu kita buktikan sendiri: urutan default membandingkan segala sesuatu sebagai string, dan keduanya mengubah array asal.

Chapter ini membongkar kedua perilaku itu, membangun comparator yang benar untuk angka dan nama Indonesia, lalu memperkenalkan pasangan modern toSorted, toReversed, dan with yang bekerja pada salinan.

sort Mengubah Array Asal #

Aturan pertama yang wajib dipahami: sort bekerja langsung pada array yang dipanggilnya — tidak ada salinan yang dibuat. Kembaliannya pun bukan array baru, melainkan referensi array yang sama:

js
const nilai = [30, 10, 20];
const hasil = nilai.sort();
console.log(hasil === nilai);
console.log(nilai);

Output yang Dihasilkan:

text
true
[ 10, 20, 30 ]

Perbandingan === menghasilkan true — hasil dan nilai adalah array yang sama. Setelah sort dijalankan, isi nilai sudah tersusun ulang secara permanen. Bila array asal masih diperlukan dalam urutan aslinya, kita harus menyalin terlebih dahulu — cara lengkapnya ada di bagian akhir chapter dan di chapter Best Practices.

Urutan Default: Semuanya Dibandingkan sebagai String #

Tanpa argumen, sort mengonversi setiap elemen menjadi string, lalu membandingkan urutan karakternya. Untuk teks, aturan ini terasa wajar. Untuk angka, aturan ini menghasilkan urutan yang salah:

js
console.log([10, 9, 1].sort());
console.log("10" < "9");

Output yang Dihasilkan:

text
[ 1, 10, 9 ]
true

Array [10, 9, 1] seharusnya terurut [ 1, 9, 10 ], tetapi sort() menghasilkan [ 1, 10, 9 ]. Penjelasannya ada di baris kedua: sebagai string, "10" memang lebih kecil dari "9", karena perbandingan string berhenti di karakter pertama yang berbeda — "1" versus "9" — dan "1" datang lebih dulu. Angka 10000 pun kalah dari 2500 dengan alasan yang sama. Inilah jebakan sort yang paling sering menimpa pemula.

Comparator: Aturan Urutan Kita Sendiri #

sort menerima satu argumen berupa function callback yang disebut comparator. Comparator menerima dua elemen yang sedang dibandingkan — a dan b — dan aturannya berbasis tanda kembalian: hasil negatif menempatkan a sebelum b, hasil positif menempatkan b sebelum a, dan nol berarti keduanya setara. Untuk angka menaik, selisih a - b menghasilkan tepat tanda yang dibutuhkan:

js
const barang = [
  { nama: "Kabel USB", harga: 25000 },
  { nama: "Buku Catatan", harga: 15000 },
];
barang.sort((a, b) => a.harga - b.harga);
console.log(barang[0].nama);

Output yang Dihasilkan:

text
Buku Catatan

Comparator membaca properti harga dari dua object yang dibandingkan — cara membaca properti object kita pelajari di chapter sebelumnya — dan mengurangkannya. 15000 - 25000 menghasilkan negatif, sehingga Buku Catatan ditempatkan sebelum Kabel USB. Mengubah arah menjadi menurun cukup dengan membalik pengurangan menjadi b.harga - a.harga; tidak ada comparator baru yang perlu ditulis.

Satu jaminan tambahan yang perlu diketahui: sejak ES2019, spesifikasi menuntut sort bersifat stable — dua elemen yang dianggap setara oleh comparator mempertahankan urutan asalnya. Saat dua produk memiliki harga sama, produk yang lebih dulu muncul di daftar asal tetap lebih dulu muncul setelah diurutkan. Jaminan ini menjadi dasar pola pengurutan dua lapis: urutkan dulu dengan kunci sekunder, lalu urutkan sekali lagi dengan kunci utama — urutan kunci sekunder tidak rusak oleh pengurutan kedua.

Mengurutkan Nama dengan localeCompare(“id”) #

Comparator (a, b) => a - b hanya cocok untuk angka. Untuk teks, sort default sudah membandingkan string — tetapi berdasarkan kode karakter, sehingga semua huruf besar ditempatkan sebelum huruf kecil. Cara yang benar untuk nama manusia adalah localeCompare dengan kode bahasa yang diinginkan; untuk nama Indonesia, kode locale-nya "id":

js
const namaPembeli = ["Zaki", "budi"];
console.log(namaPembeli.sort());
console.log(namaPembeli.sort((a, b) => a.localeCompare(b, "id")));

Output yang Dihasilkan:

text
[ 'Zaki', 'budi' ]
[ 'budi', 'Zaki' ]

Urutan pertama memperlihatkan kelemahan default: kode karakter Z (90) lebih kecil dari b (98), sehingga "Zaki" ditempatkan di depan meskipun secara abjad b mendahului z. Comparator kedua memakai localeCompare dengan locale "id", yang memperlakukan huruf besar dan kecil setara untuk urutan dasarnya — dan hasilnya mengikuti alfabet yang diharapkan pembaca Indonesia.

reverse dan toReversed: Membalik Urutan #

reverse membalik urutan elemen array — elemen terakhir menjadi pertama. Seperti sort, method ini bermutasi pada array asal dan mengembalikan referensi yang sama. Pasangan modernnya, toReversed, mengembalikan salinan yang terbalik dan membiarkan asalnya utuh:

js
const nomorAntrian = [1, 2, 3];
console.log(nomorAntrian.reverse());
console.log(nomorAntrian);

const salinanBalik = [1, 2, 3].toReversed();
console.log(salinanBalik);

Output yang Dihasilkan:

text
[ 3, 2, 1 ]
[ 3, 2, 1 ]
[ 3, 2, 1 ]

Baris kedua membuktikan reverse mengubah nomorAntrian secara permanen — array itu kini berisi [3, 2, 1]. Pada baris ketiga, toReversed dipanggil pada array literal terpisah sehingga tidak ada yang berubah di belakang layar.

toSorted dan with: Variasi Tanpa Mutasi (ES2023) #

ES2023 melengkapi JavaScript dengan serangkaian method yang bekerja pada salinan: toSorted(comparator) mengembalikan salinan yang terurut, toReversed yang sudah kita lihat, dan with(index, nilaiBaru) mengembalikan salinan dengan satu elemen diganti pada posisi tertentu. Ketiganya tersedia penuh di Node 24 dan browser modern sejak 2023:

js
const nilaiAsal = [30, 10, 20];
console.log(nilaiAsal.toSorted());
console.log(nilaiAsal.with(1, 99));
console.log(nilaiAsal);

Output yang Dihasilkan:

text
[ 10, 20, 30 ]
[ 30, 99, 20 ]
[ 30, 10, 20 ]

toSorted() menghasilkan salinan terurut, with(1, 99) menghasilkan salinan dengan elemen index 1 diganti, dan baris terakhir menegaskan nilaiAsal tetap [ 30, 10, 20 ]. Perhatikan bahwa toSorted() tanpa comparator mewarisi kelemahan urutan string — comparator tetap diperlukan untuk angka.

Kapan sort, Kapan toSorted #

Dengan dua kubu method yang kini tersedia, keputusannya bisa dirumuskan singkat:

KondisiPilihan
Array asal tidak dipakai lagi dalam urutan lamanyasort langsung — satu langkah, tanpa salinan
Array asal masih dibutuhkan dalam urutan aslinyatoSorted, atau salin dulu lalu sort
Data bersama yang dipakai banyak bagian programSelalu varian salin — toSorted, toReversed, with

Pemakaian umum reverse juga mengikuti pola ini: setelah harga terurut menaik, toReversed() menampilkannya dari yang termahal — atau sebaliknya — tanpa menyentuh data asal. Karena sort dan reverse sering dipasangkan, memilih varian salin untuk keduanya sekaligus menjaga data asal tetap dapat dipakai ulang.

Contoh Lengkap: Mengurutkan Tanpa Kehilangan Asal #

// sorting-dan-reversing.js
// sort dengan comparator, localeCompare, reverse, dan variasi ES2023 tanpa mutasi.

// --- 1. sort() default: membandingkan sebagai string dan mengubah array asal ---
const hargaBarang = [9000, 10000, 2500];
const hasilSort = hargaBarang.sort();
console.log(hasilSort);
console.log(hargaBarang); // array asal ikut berubah
console.log(hasilSort === hargaBarang);

// --- 2. Comparator angka: (a, b) => a - b ---
const stokGudang = [9000, 10000, 2500];
console.log(stokGudang.sort((a, b) => a - b)); // menaik
console.log(stokGudang.sort((a, b) => b - a)); // menurun

// --- 3. Nama: sort default vs localeCompare("id") ---
const namaPembeli = ["budi", "Zaki", "Siti", "Andi"];
console.log(namaPembeli.sort());
console.log(namaPembeli.sort((a, b) => a.localeCompare(b, "id")));

// --- 4. reverse dan toReversed ---
const nomorAntrian = [1, 2, 3];
console.log(nomorAntrian.reverse());

const salinanBalik = [1, 2, 3].toReversed();
console.log(salinanBalik);

// --- 5. toSorted dan with: salinan terurut dan salinan terkoreksi ---
const nilaiAsal = [30, 10, 20];
console.log(nilaiAsal.toSorted());
console.log(nilaiAsal); // tetap [30, 10, 20]
console.log(nilaiAsal.with(0, 99));
console.log(nilaiAsal);

Output yang Dihasilkan:

text
[ 10000, 2500, 9000 ]
[ 10000, 2500, 9000 ]
true
[ 2500, 9000, 10000 ]
[ 10000, 9000, 2500 ]
[ 'Andi', 'Siti', 'Zaki', 'budi' ]
[ 'Andi', 'budi', 'Siti', 'Zaki' ]
[ 3, 2, 1 ]
[ 3, 2, 1 ]
[ 10, 20, 30 ]
[ 30, 10, 20 ]
[ 99, 10, 20 ]
[ 30, 10, 20 ]

Mari kita telaah baris-baris pentingnya:

  1. Baris 6 (const hasilSort = hargaBarang.sort()): urutan default menjadikan "10000" lebih kecil dari "2500", sehingga hasilnya [ 10000, 2500, 9000 ] — salah sebagai angka, benar sebagai string.
  2. Baris 8–9 (console.log(hargaBarang) dan hasilSort === hargaBarang): array asal ikut tersusun ulang, dan perbandingan true membuktikan sort mengembalikan referensi yang sama.
  3. Baris 13 (stokGudang.sort((a, b) => a - b)): comparator selisih menghasilkan urutan menaik yang benar: [ 2500, 9000, 10000 ].
  4. Baris 14 (stokGudang.sort((a, b) => b - a)): pembalikan selisih menghasilkan urutan menurun — satu comparator, dua arah.
  5. Baris 18–19 (namaPembeli.sort() lalu localeCompare): default menempatkan semua huruf besar lebih dulu — Andi, Siti, Zaki, lalu budi — sedangkan localeCompare("id") mengembalikan urutan abjad yang benar.
  6. Baris 23 (nomorAntrian.reverse()): pembalikan bermutasi; setelah baris ini, nomorAntrian berisi [3, 2, 1].
  7. Baris 30–33 (toSorted dan with): kedua method mengembalikan salinan — terurut dan terkoreksi — sementara dua baris console.log(nilaiAsal) menegaskan array asal tetap [ 30, 10, 20 ].

Mengurutkan, membalik, dan mengoreksi array kini bisa dilakukan tanpa kehilangan data asal. Chapter berikutnya memindahkan fokus dari isi array ke variabel penampungnya: membongkar array ke dalam beberapa variabel sekaligus dengan destructuring.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

sorting-dan-reversing.js

Unduh berkas
javascript
// sorting-dan-reversing.js
// sort dengan comparator, localeCompare, reverse, dan variasi ES2023 tanpa mutasi.

// --- 1. sort() default: membandingkan sebagai string dan mengubah array asal ---
const hargaBarang = [9000, 10000, 2500];
const hasilSort = hargaBarang.sort();
console.log(hasilSort);
console.log(hargaBarang); // array asal ikut berubah
console.log(hasilSort === hargaBarang);

// --- 2. Comparator angka: (a, b) => a - b ---
const stokGudang = [9000, 10000, 2500];
console.log(stokGudang.sort((a, b) => a - b)); // menaik
console.log(stokGudang.sort((a, b) => b - a)); // menurun

// --- 3. Nama: sort default vs localeCompare("id") ---
const namaPembeli = ["budi", "Zaki", "Siti", "Andi"];
console.log(namaPembeli.sort());
console.log(namaPembeli.sort((a, b) => a.localeCompare(b, "id")));

// --- 4. reverse dan toReversed ---
const nomorAntrian = [1, 2, 3];
console.log(nomorAntrian.reverse());

const salinanBalik = [1, 2, 3].toReversed();
console.log(salinanBalik);

// --- 5. toSorted dan with: salinan terurut dan salinan terkoreksi ---
const nilaiAsal = [30, 10, 20];
console.log(nilaiAsal.toSorted());
console.log(nilaiAsal); // tetap [30, 10, 20]
console.log(nilaiAsal.with(0, 99));
console.log(nilaiAsal);