JavaScript

Belum masuk. Progresmu tidak tersimpan.

Masuk
  • Bab 12 dari 12
  • 35 menit
  • 1 latihan kode
  • 4 soal kuis

JavaScript Modern: ES2016 sampai ES2023

Di bab ini (13 bagian)
  1. Tujuan
  2. JavaScript terus bertambah tiap tahun
  3. Method kecil yang menghemat banyak baris
  4. Dukungan browser dan transpiler
  5. async/await: Promise yang terbaca lurus
  6. Optional chaining dan nullish coalescing
  7. BigInt dan logical assignment
  8. Private field dan static block
  9. Array.at, Object.hasOwn, dan structuredClone
  10. Timeline ES2016 sampai ES2023
  11. Cheat sheet: kapan pakai apa
  12. Kesalahan umum
  13. Rangkuman

Tujuan bab ini

  • Mengenal method baru array, string, number, dan object yang dipakai sehari-hari.
  • Menulis kode asynchronous dengan async/await dan menangani error dengan try/catch.
  • Memakai ?., ??, logical assignment, dan private field # dengan tepat.
  • Memahami peran transpiler dan urutan fitur dari ES2016 sampai ES2023.

JavaScript terus bertambah tiap tahun

Sejak ES2015 (ES6), komite TC39 merilis versi baru setiap tahun. Namanya mengikuti tahun: ES2016, ES2017, dan seterusnya. Tiap rilis biasanya kecil, tapi kalau dikumpulkan, cara menulis JavaScript sekarang terasa jauh lebih enak dibanding sepuluh tahun lalu. Bab ini merangkum yang paling sering kamu temui di kode nyata.

Method kecil yang menghemat banyak baris

const buah = ["apel", "jeruk", NaN];
buah.includes("jeruk");          // true (ES2016)
buah.includes(NaN);              // true, indexOf(NaN) malah -1

Array.from("halo");              // [ 'h', 'a', 'l', 'o' ]
Array.from({ length: 3 }, (_, i) => i * 2); // [ 0, 2, 4 ]

"7".padStart(3, "0");            // '007' (ES2017)
"Bab 1".padEnd(8, ".");          // 'Bab 1...'
"  halo  ".trimStart();          // 'halo  ' (ES2019)

Number.isInteger(5.0);           // true
Number.isNaN("abc");             // false, beda dengan isNaN("abc") yang true
Math.trunc(-4.7);                // -4

Untuk objek, ada trio yang sangat berguna:

const harga = { kopi: 18000, teh: 12000 };
Object.keys(harga);      // [ 'kopi', 'teh' ]
Object.values(harga);    // [ 18000, 12000 ]
Object.entries(harga);   // [ [ 'kopi', 18000 ], [ 'teh', 12000 ] ] (ES2017)

// kebalikannya, ES2019:
const diskon = Object.fromEntries(
  Object.entries(harga).map(([k, v]) => [k, v * 0.9])
);
console.log(diskon); // { kopi: 16200, teh: 10800 }

Pola entries lalu map lalu fromEntries adalah cara standar "memetakan" isi objek. Dari ES2019 juga ada flat dan flatMap:

[1, [2, [3, 4]]].flat(2);                     // [ 1, 2, 3, 4 ]
["a b", "c"].flatMap((s) => s.split(" "));    // [ 'a', 'b', 'c' ]

Dukungan browser dan transpiler

Browser modern (Chrome, Firefox, Edge, Safari) dan Node.js sudah mendukung hampir semua fitur di bab ini secara native. Kalau proyekmu harus jalan di browser lama, ada Babel, sebuah transpiler yang menerjemahkan sintaks baru ke sintaks lama. Contohnya a?.b diubah menjadi pengecekan a == null ? undefined : a.b. Lalu bundler seperti Vite atau Webpack menggabungkan banyak modul menjadi file siap pakai. Situs seperti caniuse.com membantu mengecek fitur mana yang aman dipakai.

async/await: Promise yang terbaca lurus

async/await (ES2017) adalah gula sintaksis di atas Promise. Fungsi async selalu mengembalikan Promise, dan await menjeda fungsi itu sampai Promise selesai, tanpa membekukan sisa program.

const ambilUser = async (id) => ({ id, nama: "Dini" });

async function sapa(id) {
  const user = await ambilUser(id);
  return `Halo ${user.nama}`;
}

sapa(1).then(console.log); // Halo Dini

Error dari Promise yang rejected bisa ditangkap dengan try/catch biasa, persis seperti kode synchronous:

async function muat(ambil) {
  try {
    const data = await ambil();
    return data.judul;
  } catch (err) {
    return `Gagal: ${err.message}`;
  } finally {
    console.log("loading selesai");
  }
}

Hati-hati dengan await berurutan untuk tugas yang tidak saling bergantung. Dua await berturut-turut berarti menunggu satu per satu. Kalau keduanya independen, jalankan paralel:

const [user, post] = await Promise.all([ambilUser(1), ambilPost(1)]);

Satu lagi dari ES2022: top-level await. Di dalam modul (bukan script biasa), await boleh dipakai langsung di luar fungsi.

Optional chaining dan nullish coalescing

Dua operator ES2020 ini sahabat terbaik saat datanya mungkin kosong.

const user = { profil: null };

user.profil.nama;          // TypeError: Cannot read properties of null
user.profil?.nama;         // undefined, aman
user.sapa?.();             // undefined, method tidak ada pun aman

const input = 0;
input || 10;               // 10, karena 0 falsy
input ?? 10;               // 0, karena 0 bukan null/undefined
user.profil?.nama ?? "Tamu"; // 'Tamu'

?. berhenti dan menghasilkan undefined begitu menemukan null atau undefined. ?? hanya menganggap null dan undefined sebagai kosong, sedangkan || juga membuang 0, "", dan false. Untuk nilai default angka atau teks, ?? hampir selalu pilihan yang benar.

BigInt dan logical assignment

Number hanya presisi sampai Number.MAX_SAFE_INTEGER (9007199254740991). Lewat dari itu, angka mulai dibulatkan. BigInt (ES2020) ditulis dengan akhiran n dan presisinya tak terbatas.

9007199254740993;          // 9007199254740992, salah satu angka
9007199254740993n;         // 9007199254740993n, tepat
typeof 10n;                // 'bigint'
10n + 5;                   // TypeError: Cannot mix BigInt and other types
10n + BigInt(5);           // 15n

Logical assignment (ES2021) menggabungkan operator logika dan =:

let opsi;
opsi ??= {};          // isi hanya kalau null/undefined
opsi.tema ||= "gelap"; // isi kalau falsy
opsi.tema &&= opsi.tema.toUpperCase(); // ubah kalau truthy
console.log(opsi);    // { tema: 'GELAP' }

Bonus ES2021: replaceAll. "a-b-c".replace("-", "+") hanya mengganti yang pertama ('a+b-c'), sedangkan "a-b-c".replaceAll("-", "+") mengganti semuanya ('a+b+c').

Private field dan static block

Ingat konvensi _saldo di bab class? ES2022 memberi privasi sungguhan dengan #.

class Akun {
  #saldo = 0;
  static bank;

  static {
    Akun.bank = "Bank Matcha"; // jalan sekali saat class dibuat
  }

  setor(jumlah) {
    this.#saldo += jumlah;
    return this;
  }

  get saldo() {
    return this.#saldo;
  }
}

const a = new Akun().setor(50000);
console.log(a.saldo);   // 50000
console.log(Akun.bank); // Bank Matcha
// a.#saldo              -> SyntaxError, benar-benar tertutup

Array.at, Object.hasOwn, dan structuredClone

const antre = ["Ana", "Budi", "Cici"];
antre.at(-1);                         // 'Cici' (ES2022), ganti antre[antre.length - 1]
Object.hasOwn({ x: 1 }, "x");         // true (ES2022), pengganti hasOwnProperty

const asli = { tim: ["Ana"], tgl: new Date(0) };
const salinan = structuredClone(asli); // salinan dalam (deep copy)
salinan.tim.push("Budi");
console.log(asli.tim);                // [ 'Ana' ], aslinya tidak ikut berubah

structuredClone bukan bagian dari ECMAScript, melainkan API web yang tersedia di browser modern dan Node.js 17 ke atas. Ia menyalin sampai ke dalam, berbeda dari spread { ...asli } yang hanya menyalin lapisan pertama. Fungsi dan instance class tidak bisa di-clone dengan cara ini.

Timeline ES2016 sampai ES2023

VersiFitur utama
ES2016Array.prototype.includes, operator pangkat **
ES2017async/await, Object.entries/values, padStart/padEnd
ES2018object spread/rest, Promise.prototype.finally, async iteration
ES2019flat/flatMap, Object.fromEntries, trimStart/trimEnd
ES2020?., ??, BigInt, globalThis, Promise.allSettled, matchAll
ES2021logical assignment (??=, &&=, dan versi OR), replaceAll, Promise.any
ES2022private field #, static block, at(), Object.hasOwn, top-level await
ES2023findLast/findLastIndex, toSorted, toReversed, with

Cheat sheet: kapan pakai apa

KebutuhanPakai
Properti yang mungkin null?.
Nilai default yang boleh 0 atau ""??
Menunggu operasi asynchronousasync/await + try/catch
Beberapa request yang independenawait Promise.all([...])
Mengubah isi objek per keyObject.entries lalu fromEntries
Elemen terakhir array.at(-1)
Data rahasia di class#field
Salinan dalam objekstructuredClone
Angka melebihi 2^53BigInt

Kesalahan umum

  • Lupa await. const data = ambil() berisi Promise, bukan datanya, sehingga data.judul bernilai undefined.
  • Memakai await di luar fungsi async pada script biasa, hasilnya SyntaxError.
  • Memakai || untuk default angka. Stok 0 berubah menjadi nilai default; pakai ??.
  • Mencampur BigInt dan Number dalam satu operasi tanpa konversi.
  • Mengira spread menyalin dalam. Array di dalam objek masih dipakai bersama; pakai structuredClone.
  • Menyalahgunakan ?. sampai menyembunyikan bug. Pakai hanya untuk data yang memang boleh kosong.

Rangkuman

  • JavaScript rilis tiap tahun; Babel dan bundler membantu kode modern tetap jalan di browser lama.
  • async/await membuat Promise terbaca lurus, error ditangkap dengan try/catch, dan tugas independen dijalankan paralel dengan Promise.all.
  • ?. dan ?? menangani data kosong dengan aman; ??=, ||=, &&= meringkas penugasan bersyarat.
  • Fitur kecil seperti Object.fromEntries, flat, replaceAll, at, Object.hasOwn, #field, dan structuredClone menggantikan banyak kode bantu buatan sendiri.

Selesaikan bab ini

  1. 1. Baca materi
  2. 2. Latihan kode (1)
  3. 3. Kuis (4 soal)

Latihan kode: Profil aman dan dompet privat

Lengkapi:

  • async function muatProfil(ambil) memanggil await ambil() yang mengembalikan objek user atau melempar error. Kembalikan { nama, kota } dengan nama dari user.profil.nama (default "Tamu") dan kota dari user.alamat.kota (default "-"). Gunakan ?. dan ??. Bila ambil gagal, tangkap dengan try/catch dan kembalikan { error: <pesan error> }.
  • kodeInvoice(n) mengembalikan "INV-" diikuti n yang dipanjangkan jadi 4 digit dengan nol di depan. Contoh: kodeInvoice(7) menghasilkan "INV-0007".
  • class Dompet dengan private field #saldo (awal 0), method setor(jumlah), dan getter saldo.

Cek pemahaman

  1. 1Apa yang ditampilkan kode berikut?

    const stok = 0;
    console.log(stok || 10, stok ?? 10);
  2. 2Apa nilai `user.alamat?.kota` bila `user = { alamat: null }`?

  3. 3Apa yang ditampilkan kode berikut?

    const ambil = async () => ({ nama: "Dini" });
    async function nama() {
      const u = await ambil();
      return u.nama;
    }
    nama().then((n) => console.log(n));
  4. 4`structuredClone` adalah fitur ECMAScript ES2022 yang sama dengan spread `{ ...obj }`.