kodingup.camp

Beranda/JavaScript Mastery: Fundamentals

Struktur Data Primitif dan Kompleks

Modul 9 dari 164 menit bacaPrimitive and complex data structures

Isi modul

    Kenapa ini penting

    Setiap nilai di JavaScript punya tipe data. Tipe menentukan operasi apa yang bisa dilakukan: angka bisa dijumlahkan, teks bisa diubah ke huruf besar, daftar bisa diurutkan. Banyak bug pemula berasal dari salah tipe, misalnya "5" + 3 menghasilkan "53". Modul ini juga membahas satu konsep yang sering menjebak bahkan programmer berpengalaman: perbedaan by value dan by reference. Kalau kamu tidak paham ini, kamu bisa tanpa sengaja mengubah data di satu tempat dan kaget melihat data di tempat lain ikut berubah.

    Konsep inti

    Tujuh tipe primitif

    Primitif adalah nilai tunggal yang sederhana dan tidak bisa diubah (immutable). JavaScript punya 7 tipe primitif:

    Tipe Contoh Keterangan
    string "Halo", 'JS', `Hai ${nama}` Teks
    number 42, 3.14, -7, NaN, Infinity Angka (bulat maupun pecahan)
    bigint 9007199254740993n Bilangan bulat sangat besar, diakhiri n
    boolean true, false Benar atau salah
    undefined undefined Variabel sudah ada tapi belum diberi nilai
    null null Sengaja dikosongkan oleh programmer
    symbol Symbol("id") Penanda unik, dipakai di kasus lanjutan

    Perbedaan undefined dan null sering membingungkan. Analogi kursi di bioskop: undefined itu kursi yang belum pernah dijual tiketnya (belum diisi sama sekali), sedangkan null itu kursi yang sengaja dikosongkan dengan tanda "kosong" (programmer secara sadar bilang "tidak ada nilai").

    "Immutable" artinya nilainya sendiri tidak bisa diubah. "halo".toUpperCase() tidak mengubah string "halo". Method itu membuat string baru "HALO".

    Tipe kompleks: object (termasuk array dan function)

    Selain 7 primitif, semua yang lain adalah object. Object adalah wadah yang bisa menyimpan banyak nilai sekaligus.

    Object bersifat mutable: isinya bisa diubah setelah dibuat.

    Operator typeof

    typeof mengembalikan string nama tipe sebuah nilai. Ada dua keanehan yang wajib diingat:

    Ekspresi Hasil Catatan
    typeof "hai" "string"
    typeof 42 "number"
    typeof NaN "number" NaN tetap bertipe number
    typeof 10n "bigint"
    typeof true "boolean"
    typeof undefined "undefined"
    typeof null "object" Bug bersejarah sejak JavaScript pertama, dipertahankan demi kompatibilitas
    typeof Symbol() "symbol"
    typeof {} "object"
    typeof [] "object" Array juga object. Pakai Array.isArray() untuk mengecek array
    typeof function(){} "function"

    By value vs by reference

    Ini konsep terpenting di modul ini.

    Primitif disalin by value. Saat kamu menulis let b = a, nilai a disalin ke b. Keduanya terpisah. Analogi: kamu memfotokopi selembar kertas lalu memberikannya ke teman. Kalau teman mencoret fotokopinya, kertas aslimu tetap bersih.

    Object disalin by reference. Variabel object sebenarnya menyimpan alamat (referensi) ke lokasi object di memori. const b = a hanya menyalin alamatnya, jadi a dan b menunjuk ke object yang sama. Analogi: kamu memberi teman kunci duplikat rumahmu. Kalau teman memindahkan sofa, sofa di rumahmu juga pindah, karena rumahnya memang sama.

    Akibatnya:

    Contoh kode

    // Tujuh primitif dan typeof
    console.log(typeof "Halo");        // → string
    console.log(typeof 3.14);          // → number
    console.log(typeof 10n);           // → bigint
    console.log(typeof false);         // → boolean
    console.log(typeof undefined);     // → undefined
    console.log(typeof null);          // → object  (bug bersejarah!)
    console.log(typeof Symbol("id"));  // → symbol
    
    // Tipe kompleks
    console.log(typeof { a: 1 });           // → object
    console.log(typeof [1, 2, 3]);          // → object
    console.log(Array.isArray([1, 2, 3]));  // → true
    console.log(typeof function () {});     // → function
    
    // undefined vs null
    let alamat;             // belum diisi
    let nomorHp = null;     // sengaja dikosongkan
    console.log(alamat, nomorHp); // → undefined null
    
    // Primitif immutable: method membuat nilai baru
    const sapa = "halo";
    const besar = sapa.toUpperCase();
    console.log(sapa, besar); // → halo HALO
    

    By value vs by reference:

    // PRIMITIF: by value (disalin)
    let a = 10;
    let b = a;
    b = 99;
    console.log(a, b); // → 10 99  (a tidak ikut berubah)
    
    // OBJECT: by reference (alamat yang disalin)
    const user1 = { nama: "Ani", poin: 10 };
    const user2 = user1;      // user2 menunjuk object yang SAMA
    user2.poin = 50;
    console.log(user1.poin);  // → 50  (user1 ikut berubah!)
    
    // Perbandingan object membandingkan alamat
    console.log({ x: 1 } === { x: 1 }); // → false
    console.log(user1 === user2);       // → true
    
    // Salinan dangkal dengan spread
    const user3 = { ...user1 };
    user3.poin = 0;
    console.log(user1.poin, user3.poin); // → 50 0
    
    // Masalah salinan dangkal: object di dalam object masih berbagi referensi
    const asli = { nama: "Budi", alamat: { kota: "Solo" } };
    const dangkal = { ...asli };
    dangkal.alamat.kota = "Klaten";
    console.log(asli.alamat.kota);       // → Klaten (ikut berubah)
    
    // Salinan dalam dengan structuredClone
    const asli2 = { nama: "Citra", alamat: { kota: "Solo" } };
    const dalam = structuredClone(asli2);
    dalam.alamat.kota = "Klaten";
    console.log(asli2.alamat.kota);      // → Solo (aman)
    
    // Array juga by reference
    const daftar = [1, 2, 3];
    const salinan = [...daftar];
    salinan.push(4);
    console.log(daftar, salinan); // → [ 1, 2, 3 ] [ 1, 2, 3, 4 ]
    

    Kesalahan umum

    1. Mengecek null dengan typeof x === "null". Hasil typeof null adalah "object". Cek dengan x === null.
    2. Mengecek array dengan typeof. typeof [] bernilai "object". Gunakan Array.isArray(x).
    3. Mengira const b = a membuat salinan object. Itu hanya menyalin referensi. Gunakan spread atau structuredClone.
    4. Mengira spread menyalin sampai ke dalam. Spread hanya menyalin satu tingkat. Untuk data bersarang, gunakan structuredClone.
    5. Membandingkan dua object atau array dengan ===. [1, 2] === [1, 2] bernilai false. Bandingkan isinya, misalnya elemen per elemen atau dengan JSON.stringify untuk kasus sederhana.

    Latihan

    1. Mudah, Buat satu variabel untuk masing-masing tipe primitif (7 variabel), lalu cetak typeof setiap variabel.
    2. Sedang, Buat function tipeAsli(x) yang mengembalikan "null" untuk null, "array" untuk array, dan hasil typeof biasa untuk yang lain.
    3. Menantang, Diberikan const produk = { nama: "Kaos", harga: 80000, varian: ["S", "M"] }. Buat salinan bernama produkBaru dengan harga 90000 dan varian ditambah "L", tanpa mengubah produk asli sedikit pun. Buktikan dengan console.log.
    Lihat solusi

    1.

    const s = "teks";
    const n = 7;
    const big = 7n;
    const bool = true;
    let u;
    const kosong = null;
    const sym = Symbol("kunci");
    for (const nilai of [s, n, big, bool, u, kosong, sym]) {
      console.log(typeof nilai);
    }
    // → string, number, bigint, boolean, undefined, object, symbol (satu per baris)
    

    2.

    function tipeAsli(x) {
      if (x === null) return "null";
      if (Array.isArray(x)) return "array";
      return typeof x;
    }
    console.log(tipeAsli(null));   // → null
    console.log(tipeAsli([1]));    // → array
    console.log(tipeAsli({}));     // → object
    console.log(tipeAsli("a"));    // → string
    

    3.

    const produk = { nama: "Kaos", harga: 80000, varian: ["S", "M"] };
    
    const produkBaru = {
      ...produk,
      harga: 90000,
      varian: [...produk.varian, "L"], // array baru, bukan referensi lama
    };
    
    console.log(produk);     // → { nama: 'Kaos', harga: 80000, varian: [ 'S', 'M' ] }
    console.log(produkBaru); // → { nama: 'Kaos', harga: 90000, varian: [ 'S', 'M', 'L' ] }
    

    Kalau kamu menulis produkBaru.varian.push("L") setelah spread biasa, array varian milik produk juga ikut bertambah, karena keduanya berbagi array yang sama.

    Ringkasan

    Kuis pemahaman

    Pilih satu jawaban per soal. Penjelasan muncul setelah kamu menjawab.