kodingup.camp

Beranda/JavaScript Mastery: Object & Data

Operasi Dasar Nilai Primitif

Modul 7 dari 144 menit bacaCore Primitive Operations

Isi modul

    Kenapa ini penting

    JavaScript punya tujuh tipe primitif: string, number, bigint, boolean, undefined, null, dan symbol. Semua yang bukan primitif adalah object (termasuk array dan function). Perbedaan ini bukan sekadar teori. Ia menentukan bagaimana data disalin, dibandingkan, dan diubah.

    Pernah heran kenapa "halo".toUpperCase() bisa jalan padahal string itu bukan object? Atau kenapa [1, 2] === [1, 2] bernilai false? Atau kenapa str[0] = "X" tidak mengubah apa-apa? Semua jawabannya ada di modul ini. Pemahaman tentang perbandingan nilai (==, ===, Object.is) juga sangat penting, karena salah memilih operator perbandingan adalah sumber bug logika yang klasik.

    Konsep inti

    Primitif vs object: nilai vs referensi

    Ini juga berlaku saat mengirim argumen ke function. Primitif dikirim sebagai salinan; object dikirim sebagai salinan alamat, sehingga function bisa mengubah isi object aslinya.

    Wrapper object dan autoboxing

    Primitif tidak punya method. Lalu bagaimana "halo".length atau (3.14159).toFixed(2) bisa bekerja? Saat kamu mengakses properti pada primitif, JavaScript sementara membungkusnya dengan wrapper object (String, Number, Boolean), memanggil method-nya, lalu membuang bungkus itu. Proses ini disebut autoboxing. Analogi: kamu meminjam sarung tangan khusus sebentar untuk memegang sesuatu yang panas, lalu mengembalikannya.

    Kamu jangan membuat wrapper secara manual dengan new String("x") atau new Number(5). Hasilnya object, bukan primitif, sehingga typeof bernilai "object", perbandingan === gagal, dan new Boolean(false) justru truthy. Memanggil String(x) atau Number(x) tanpa new itu aman dan menghasilkan primitif (itulah konversi eksplisit dari modul 6).

    Immutability (tidak bisa diubah)

    Semua primitif bersifat immutable. Method string seperti toUpperCase, replace, atau trim tidak pernah mengubah string aslinya; mereka mengembalikan string baru. str[0] = "X" diabaikan (atau melempar TypeError di strict mode). Untuk "mengubah" string, kamu harus membuat string baru dan menyimpannya kembali ke variabel.

    Perlu dibedakan: variabel let bisa diganti isinya (reassign), tapi nilai primitif di dalamnya tidak pernah diubah di tempat.

    Perbandingan nilai

    Operator Cara kerja Contoh menarik
    == mengonversi tipe dulu (loose equality) "1" == 1 → true, null == undefined → true
    === tipe dan nilai harus sama (strict equality) "1" === 1 → false
    Object.is seperti ===, kecuali dua kasus khusus Object.is(NaN, NaN) → true, Object.is(0, -0) → false

    Gunakan === sebagai default. Satu-satunya pemakaian == yang umum dan masih dianggap wajar adalah x == null, yang bernilai true untuk null maupun undefined.

    Untuk object, semua operator di atas membandingkan referensi, bukan isi. Dua object dengan isi sama tetap tidak sama kalau alamatnya berbeda.

    NaN adalah satu-satunya nilai yang tidak sama dengan dirinya sendiri (NaN === NaN → false). Itu sebabnya ada Number.isNaN() dan Object.is().

    Contoh kode

    "use strict";
    
    // 1) typeof untuk semua tipe
    console.log(typeof "teks", typeof 42, typeof 10n, typeof true);       // → string number bigint boolean
    console.log(typeof undefined, typeof Symbol(), typeof {}, typeof []); // → undefined symbol object object
    console.log(typeof null);           // → object (bug lama JavaScript yang dipertahankan)
    console.log(typeof function () {}); // → function
    console.log(Array.isArray([]));     // → true (cara benar mengecek array)
    
    // 2) Nilai vs referensi
    let a = 10;
    let b = a;
    b = 20;
    console.log(a, b); // → 10 20
    
    const x = { skor: 10 };
    const y = x;
    y.skor = 99;
    console.log(x.skor); // → 99
    
    function tambahSatu(angka, objek) {
      angka += 1;
      objek.nilai += 1;
    }
    let n = 1;
    const o = { nilai: 1 };
    tambahSatu(n, o);
    console.log(n, o.nilai); // → 1 2  (primitif tetap, isi object berubah)
    
    // 3) Autoboxing: primitif meminjam method dari wrapper
    const kata = "javascript";
    console.log(kata.length, kata.toUpperCase(), (3.14159).toFixed(2)); // → 10 JAVASCRIPT 3.14
    console.log(typeof kata); // → string (tetap primitif)
    
    // 4) Jangan pakai new String / new Boolean
    const s1 = "abc";
    const s2 = new String("abc");
    console.log(typeof s2, s1 === s2, s1 == s2); // → object false true
    const palsu = new Boolean(false);
    console.log(palsu ? "truthy!" : "falsy"); // → truthy! (object selalu truthy)
    
    // 5) Immutability string
    let salam = "halo";
    salam.toUpperCase();         // hasil dibuang, salam tidak berubah
    console.log(salam);          // → halo
    salam = salam.toUpperCase(); // simpan string baru ke variabel
    console.log(salam);          // → HALO
    try {
      salam[0] = "J";            // strict mode: melempar TypeError
    } catch (err) {
      console.log(err.constructor.name); // → TypeError
    }
    
    // 6) ==, ===, Object.is
    console.log("1" == 1, "1" === 1);                   // → true false
    console.log(0 == "", 0 == false);                   // → true true (membingungkan, hindari ==)
    console.log(null == undefined, null === undefined); // → true false
    console.log(NaN === NaN, Object.is(NaN, NaN));      // → false true
    console.log(0 === -0, Object.is(0, -0));            // → true false
    
    // x == null: pola sah untuk mengecek null ATAU undefined
    const cek = (v) => (v == null ? "kosong" : "ada");
    console.log(cek(null), cek(undefined), cek(0)); // → kosong kosong ada
    
    // 7) Object dibandingkan berdasarkan referensi
    console.log([1, 2] === [1, 2]); // → false
    const arr = [1, 2];
    const sama = arr;
    console.log(arr === sama);      // → true
    // Bandingkan isi sederhana (untuk data JSON-friendly)
    console.log(JSON.stringify([1, 2]) === JSON.stringify([1, 2])); // → true
    

    Kesalahan umum

    1. Memanggil method string tanpa menyimpan hasilnya. nama.trim() saja tidak mengubah nama. Tulis nama = nama.trim() atau simpan ke variabel baru.
    2. Memakai == untuk perbandingan sehari-hari. Aturan konversinya rumit (0 == "" bernilai true). Pakai ===.
    3. Mengecek NaN dengan === NaN. Selalu false. Pakai Number.isNaN(x) atau Object.is(x, NaN).
    4. Memakai typeof untuk mengecek array atau null. typeof [] dan typeof null sama-sama "object". Pakai Array.isArray(x) dan x === null.
    5. Membuat wrapper dengan new String/new Number/new Boolean. Hasilnya object yang perilakunya aneh. Pakai literal atau panggil tanpa new untuk konversi.

    Latihan

    1. Mudah, Buat function jenis(nilai) yang mengembalikan "array" untuk array, "null" untuk null, dan hasil typeof untuk lainnya.
    2. Sedang, Diberikan let kode = " abc-123 ". Ubah variabel itu menjadi "ABC-123" (tanpa spasi, huruf besar) dengan method string, dan buktikan bahwa string lama tidak "dimodifikasi" melainkan diganti.
    3. Menantang, Buat function samaPersis(a, b) yang mengembalikan true jika Object.is(a, b), dan untuk dua array satu level, membandingkan panjang dan setiap elemennya dengan Object.is.
    Lihat solusi
    // 1) Mudah
    function jenis(nilai) {
      if (Array.isArray(nilai)) return "array";
      if (nilai === null) return "null";
      return typeof nilai;
    }
    console.log(jenis([]), jenis(null), jenis(5), jenis("a")); // → array null number string
    
    // 2) Sedang
    let kode = "  abc-123  ";
    const lama = kode;
    kode = kode.trim().toUpperCase();
    console.log(kode);                 // → ABC-123
    console.log(JSON.stringify(lama)); // → "  abc-123  " (string lama tetap utuh)
    
    // 3) Menantang
    function samaPersis(a, b) {
      if (Object.is(a, b)) return true;
      if (Array.isArray(a) && Array.isArray(b)) {
        return a.length === b.length && a.every((nilai, i) => Object.is(nilai, b[i]));
      }
      return false;
    }
    console.log(samaPersis(NaN, NaN));           // → true
    console.log(samaPersis([1, NaN], [1, NaN])); // → true
    console.log(samaPersis([0], [-0]));          // → false
    console.log(samaPersis({}, {}));             // → false
    

    Ringkasan

    Kuis pemahaman

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