Budi ingin menampilkan sambutan di layar kasir kantin: nama pelanggan, jumlah poin, dan keterangan status harus digabung menjadi satu kalimat. Dengan operator +, kalimat itu lahir dari rangkaian tanda kutip, tanda plus, dan spasi yang harus dihitung satu per satu. Satu tanda kutip yang keliru posisinya cukup membuat kalimatnya berantakan.

JavaScript modern menyediakan cara yang lebih rapi: template literal. String yang ditulis dengan tanda backtick (`) dapat menyisipkan nilai, memuat ekspresi, dan menampung banyak baris sekaligus. Chapter ini membahas interpolasi ${}, string multi-baris, template literal bersarang, penulisan karakter khusus, lalu menutup dengan studi kasus struk pesanan.

Dari Concatenation ke Template Literal #

Aturan template literal: string ditulis di antara dua backtick, dan nilai disisipkan lewat slot ${ekspresi}. Saat program berjalan, interpreter menghitung ekspresi di dalam ${}, mengonversi hasilnya menjadi string, lalu menempelkannya pada posisi slot tersebut.

js
const nama = "Budi";
const poin = 1250;
const sambutanLama = "Halo, " + nama + "! Poin kamu: " + poin + ".";
const sambutanBaru = `Halo, ${nama}! Poin kamu: ${poin}.`;
console.log(sambutanLama);
console.log(sambutanBaru);

Output yang Dihasilkan:

text
Halo, Budi! Poin kamu: 1250.
Halo, Budi! Poin kamu: 1250.

Kedua baris menghasilkan teks yang identik, tetapi versi backtick nyaris dibaca seperti kalimat jadinya. Tanda kutip di sekitar tiap potongan kata dan tanda + penyambung tidak diperlukan lagi.

  1. Baris 3 (sambutanLama): concatenation lama — empat potongan string dan tiga operator + untuk menyambungnya.
  2. Baris 4 (sambutanBaru): template literal — ${nama} dan ${poin} adalah slot yang diisi nilai variabel secara langsung.
  3. Baris 5–6: kedua variabel dicetak dan menghasilkan teks yang sama persis.

Ekspresi di Dalam Interpolasi #

Isi ${} tidak terbatas pada nama variabel. Setiap ekspresi JavaScript boleh ditulis di sana: perhitungan aritmetika, perbandingan dengan ternary, bahkan pemanggilan method.

js
const harga = 5000;
const jumlah = 3;
console.log(`Total: Rp${harga * jumlah}`);
console.log(`Kategori: ${jumlah >= 3 ? "pembeli besar" : "reguler"}`);
console.log(`Panjang nama: ${"Siti".length} karakter`);
console.log(`Kode: ${"kopi".toUpperCase()}`);

Output yang Dihasilkan:

text
Total: Rp15000
Kategori: pembeli besar
Panjang nama: 4 karakter
Kode: KOPI

Baris kedua menyisipkan hasil ternary dari section Operators: syarat jumlah >= 3 bernilai true, sehingga teks "pembeli besar" yang dipilih. Karena seluruh isi ${} dievaluasi sebagai ekspresi, urutan pengerjaannya mengikuti aturan operator precedence biasa. Bila ekspresi makin panjang, kebiasaan yang sehat adalah menghitung dulu di variabel bernama — seperti total pada studi kasus di akhir chapter — lalu menyisipkan variabel itu.

Konversi Otomatis ke String #

Mekanisme di balik interpolasi adalah konversi: hasil ekspresi di dalam ${} selalu diubah menjadi string sebelum ditempel, dengan aturan yang sama seperti konversi otomatis pada section Values dan Types. Angka dan boolean berperilaku wajar, tetapi array dan object menghasilkan teks yang mengejutkan:

js
const angka = 42;
const bool = true;
const daftar = ["kopi", "teh"];
console.log(`Nilai: ${angka}, ${bool}, ${daftar}`);
console.log(`Object: ${{ nama: "Budi" }}`);

Output yang Dihasilkan:

text
Nilai: 42, true, kopi,teh
Object: [object Object]

Array disambung dengan koma (kopi,teh), sedangkan object literal menjadi teks [object Object] yang tidak membawa isinya sama sekali. Bila isi object perlu ditampilkan, ambil propertinya satu per satu seperti ${pendaftar.nama}, atau pakai JSON.stringify yang dibahas di section Data dan Serialization.

String Multi-baris #

Template literal mempertahankan baris baru apa adanya: kita cukup melanjutkan menulis di baris berikutnya tanpa \n dan tanpa operator penyambung. Perbandingan berikut membuktikan hasil kedua cara itu identik:

js
const menu = `Kopi Gayo
Teh Tarik
Roti Bakar`;
const menuLama = "Kopi Gayo\nTeh Tarik\nRoti Bakar";
console.log(menu);
console.log(menu === menuLama);

Output yang Dihasilkan:

text
Kopi Gayo
Teh Tarik
Roti Bakar
true

Hasil true pada baris terakhir menegaskan bahwa string multi-baris dan string dengan \n bernilai sama. Pilih sesuai konteks: template multi-baris nyaman untuk teks tampilan yang panjang, sedangkan \n praktis untuk string pendek yang tetap ditulis dalam satu baris kode.

Satu hal yang perlu dijaga: template literal menyalin baris persis seperti yang ditulis, termasuk baris kosong. Menambah baris kosong di awal atau akhir template menambah karakter baris baru pada hasil — keluaran console.log pun ikut bertambah baris kosongnya.

Template Literal Bersarang #

Slot ${} boleh berisi template literal lain. Pola yang paling sering dipakai: method map menyusun tiap baris dengan template literalnya sendiri, join("\n") menyambung semua barisnya, lalu hasilnya disisipkan ke template induk.

js
const pesanan = [
  { nama: "Nasi Goreng", harga: 15000 },
  { nama: "Es Teh Manis", harga: 5000 },
];
const baris = pesanan
  .map((item, i) => `${i + 1}. ${item.nama} - Rp${item.harga}`)
  .join("\n");
console.log(`Daftar Pesanan:
${baris}`);

Output yang Dihasilkan:

text
Daftar Pesanan:
1. Nasi Goreng - Rp15000
2. Es Teh Manis - Rp5000

Kedalaman interpolasinya menumpuk: template induk menyisipkan ${baris}, sedangkan baris sendiri lahir dari template literal di dalam callback map yang juga menyisipkan ${i + 1}, ${item.nama}, dan ${item.harga}. Struktur bertingkat seperti ini terasa padat dibaca sekali jalan, tetapi tiap lapisannya hanya mengerjakan satu tugas kecil.

Karakter Khusus di Dalam Template Literal #

Dua karakter perlu perlakuan khusus: backtick yang mengakhiri string, dan ${ yang membuka interpolasi. Keduanya dituliskan secara harfiah dengan bantuan garis miring terbalik: \`` untuk backtick dan ${` untuk tanda dolar. Adapun tanda kutip tunggal maupun ganda tidak perlu diloloskan — di dalam template literal keduanya diperlakukan sebagai karakter biasa.

js
console.log(`Siti berkata, "stok kopi sudah masuk".`);
console.log(`Sintaksnya ditulis \${nama}.`);
console.log(`Tanda backtick sendiri ditulis \` seperti ini.`);

Output yang Dihasilkan:

text
Siti berkata, "stok kopi sudah masuk".
Sintaksnya ditulis ${nama}.
Tanda backtick sendiri ditulis ` seperti ini.

Baris kedua dan ketiga menunjukkan efek garis miring terbalik: ${nama} dicetak sebagai teks biasa, bukan diinterpolasi, dan backtick muncul tanpa mengakhiri string.

Studi Kasus: Struk Pesanan Kantin #

Sekarang kita rangkai semuanya. Berkas berikut mencetak struk pesanan kantin: menu disusun dengan map dan join, total dihitung dengan reduce, dan seluruh struk disusun sebagai satu template literal multi-baris.

// struk-pesanan.js
// Budi mencetak struk pesanan kantin dengan template literal.

const pelanggan = "Budi";
const kasir = "Siti";

const pesanan = [
  { nama: "Nasi Goreng", harga: 15000, jumlah: 1 },
  { nama: "Es Teh Manis", harga: 5000, jumlah: 2 },
];

const total = pesanan.reduce(
  (subtotal, item) => subtotal + item.harga * item.jumlah,
  0
);

const barisMenu = pesanan
  .map((item, i) => `${i + 1}. ${item.nama} x${item.jumlah} - Rp${item.harga * item.jumlah}`)
  .join("\n");

const struk = `Toko Kantin Siti
Kasir: ${kasir}
--------------------
${barisMenu}
--------------------
Total: Rp${total}
Status: ${total > 20000 ? "diskon member" : "harga reguler"}
${"=".repeat(20)}
Terima kasih, ${pelanggan}!`;

console.log(struk);

Output yang Dihasilkan:

text
Toko Kantin Siti
Kasir: Siti
--------------------
1. Nasi Goreng x1 - Rp15000
2. Es Teh Manis x2 - Rp10000
--------------------
Total: Rp25000
Status: diskon member
====================
Terima kasih, Budi!

Jalankan dengan node struk-pesanan.js dan bandingkan struknya. Mari kita telaah baris-baris pentingnya:

  1. Baris 12 (pesanan.reduce(...)): akumulator menjumlahkan harga * jumlah tiap item dari nilai awal 0, menghasilkan 25000.
  2. Baris 18: template literal di dalam callback map menyusun tiap baris menu; ${i + 1} memberi nomor urut dan ${item.harga * item.jumlah} menghitung subtotal barisnya.
  3. Baris 19 (join("\n")): array baris menu disambung menjadi satu string multi-baris agar siap disisipkan.
  4. Baris 27: ternary di dalam slot ${} memilih label status; karena total > 20000 bernilai true, teks "diskon member" yang masuk ke struk.
  5. Baris 28 (${"=".repeat(20)}): metode repeat dari chapter String Methods menghasilkan garis pembatas sepanjang 20 karakter.

Template literal menuntaskan masalah penyusunan teks. Pertanyaan berikutnya berpindah ke arah sebaliknya: bagaimana mencari teks tertentu di dalam string — mulai dari kata persis hingga semua kemunculan sebuah kode — dan itulah bahan chapter berikutnya.

Berkas Sumber

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

struk-pesanan.js

Unduh berkas
javascript
// struk-pesanan.js
// Budi mencetak struk pesanan kantin dengan template literal.

const pelanggan = "Budi";
const kasir = "Siti";

const pesanan = [
  { nama: "Nasi Goreng", harga: 15000, jumlah: 1 },
  { nama: "Es Teh Manis", harga: 5000, jumlah: 2 },
];

const total = pesanan.reduce(
  (subtotal, item) => subtotal + item.harga * item.jumlah,
  0
);

const barisMenu = pesanan
  .map((item, i) => `${i + 1}. ${item.nama} x${item.jumlah} - Rp${item.harga * item.jumlah}`)
  .join("\n");

const struk = `Toko Kantin Siti
Kasir: ${kasir}
--------------------
${barisMenu}
--------------------
Total: Rp${total}
Status: ${total > 20000 ? "diskon member" : "harga reguler"}
${"=".repeat(20)}
Terima kasih, ${pelanggan}!`;

console.log(struk);