Bab 3: Objek — Dasar
Sampai sini kamu udah kenal tipe data primitif: string, number, boolean, dll. Sekarang kita masuk ke dunia objek — tipe data yang jauh lebih powerful dan jadi fondasi hampir semua hal di JavaScript.
3.1 Objek (Objects)
Apa Itu Objek?
Kalau primitif itu kayak satu lembar catatan (cuma simpan satu nilai), objek itu kayak lemari arsip — bisa simpan banyak data sekaligus, masing-masing punya label (nama).
// Lemari arsip bernama "user"
const user = {
nama: "Budi",
umur: 25,
sudahMenikah: false
};Setiap data di dalam objek disebut property (properti). Formatnya: kunci: nilai.
Membuat Objek
Ada 2 cara:
// 1. Object literal (PALING UMUM — pakai ini)
const mobil = {
merk: "Toyota",
tahun: 2020
};
// 2. Object constructor (jarang dipakai)
const mobil2 = new Object();
mobil2.merk = "Honda";Mengakses Properti
const user = {
nama: "Budi",
umur: 25
};
// Dot notation (paling sering)
console.log(user.nama); // "Budi"
// Bracket notation (untuk nama properti yang "aneh")
console.log(user["umur"]); // 25Kapan pakai bracket? Kalau nama properti-nya:
- Mengandung spasi:
user["suka makan"] - Dari variabel:
user[kunciDariVariabel] - Mengandung karakter spesial
const user = {
"suka kucing": true
};
// Ini ERROR:
// console.log(user.suka kucing);
// Ini BENAR:
console.log(user["suka kucing"]); // true
// Dari variabel:
const kunci = "suka kucing";
console.log(user[kunci]); // trueMenambah, Mengubah, Menghapus Properti
const user = {
nama: "Budi"
};
// Tambah properti baru
user.umur = 25;
user.kota = "Jakarta";
// Ubah properti
user.nama = "Andi";
// Hapus properti
delete user.kota;
console.log(user); // { nama: "Andi", umur: 25 }Kok
consttapi bisa diubah? Karenaconstcuma menjaga agar variabelusertidak bisa di-reassign ke objek lain. Isi di dalamnya tetap bisa diubah. Analoginya: alamat rumah tetap, tapi furniture di dalam rumah boleh diganti.
Computed Properties
Nama properti bisa diambil dari variabel saat membuat objek:
const kunci = "warna";
const tas = {
[kunci]: "merah" // sama dengan: warna: "merah"
};
console.log(tas.warna); // "merah"Property Shorthand
Kalau nama variabel sama dengan nama properti, bisa disingkat:
const nama = "Budi";
const umur = 25;
// Cara panjang:
const user1 = { nama: nama, umur: umur };
// Cara singkat (shorthand):
const user2 = { nama, umur };
// Hasilnya sama!
console.log(user2); // { nama: "Budi", umur: 25 }Mengecek Properti Ada atau Tidak
const user = { nama: "Budi", umur: 25 };
// Cara 1: Bandingkan dengan undefined
console.log(user.alamat === undefined); // true (tidak ada)
// Cara 2: Operator "in" (LEBIH AMAN)
console.log("nama" in user); // true
console.log("alamat" in user); // falseKenapa in lebih aman? Karena ada kasus langka di mana properti memang sengaja diisi undefined:
const obj = { test: undefined };
console.log(obj.test === undefined); // true — seolah tidak ada
console.log("test" in obj); // true — padahal ADA!Perulangan for...in
Untuk menelusuri semua properti objek:
const user = {
nama: "Budi",
umur: 25,
kota: "Jakarta"
};
for (let kunci in user) {
console.log(`${kunci}: ${user[kunci]}`);
}
// nama: Budi
// umur: 25
// kota: Jakarta⚠️ Jebakan: Urutan Properti
Properti dengan nama angka bulat akan diurutkan secara otomatis (ascending). Properti lain muncul sesuai urutan pembuatan.
const kodeNegara = {
"62": "Indonesia",
"1": "USA",
"81": "Jepang"
};
for (let kode in kodeNegara) {
console.log(kode); // "1", "62", "81" — BUKAN urutan asli!
}
// Trik: tambahkan "+" di depan agar tidak dianggap integer
const kodeNegara2 = {
"+62": "Indonesia",
"+1": "USA",
"+81": "Jepang"
};Buat objek buku dengan properti: judul, penulis, tahun, sudahDibaca. Lalu:
- Tambahkan properti
genre - Ubah
sudahDibacajaditrue - Hapus properti
tahun - Tampilkan semua properti dengan
for...in
3.2 Referensi Objek dan Penyalinan
Primitif vs Objek: Perbedaan Fundamental
Ini konsep yang SANGAT PENTING dan sering bikin bingung pemula.
Primitif disalin berdasarkan nilai (copy):
let pesan = "Halo";
let salinan = pesan; // salinan dapat COPY-nya
salinan = "Bye";
console.log(pesan); // "Halo" — tidak berubah!Objek disalin berdasarkan referensi (alamat):
let user = { nama: "Budi" };
let admin = user; // admin dapat ALAMAT yang sama!
admin.nama = "Andi";
console.log(user.nama); // "Andi" — IKUT BERUBAH!Bayangkan objek itu rumah, dan variabel itu kartu nama yang berisi alamat rumah.
let admin = user→ kamu fotokopi kartu nama (alamat sama, rumah sama)- Kalau
adminrenovasi rumah,userjuga lihat perubahan — karena rumahnya SATU
Perbandingan Objek
Dua variabel sama (==) hanya kalau menunjuk ke objek yang SAMA PERSIS:
let a = {};
let b = a; // referensi sama
console.log(a === b); // true
let c = {};
let d = {}; // dua objek BERBEDA (walau isinya sama)
console.log(c === d); // falseMenyalin Objek (Shallow Copy)
Kalau mau bikin salinan yang independen:
const user = { nama: "Budi", umur: 25 };
// Cara 1: Object.assign
const salinan1 = Object.assign({}, user);
// Cara 2: Spread operator (LEBIH MODERN)
const salinan2 = { ...user };
salinan2.nama = "Andi";
console.log(user.nama); // "Budi" — aman, tidak berubah!⚠️ Jebakan: Nested Object (Shallow vs Deep Copy)
Object.assign dan spread hanya menyalin level pertama. Objek di dalam objek tetap berbagi referensi!
const user = {
nama: "Budi",
alamat: {
kota: "Jakarta",
kodePos: "12345"
}
};
const salinan = { ...user };
salinan.alamat.kota = "Bandung";
console.log(user.alamat.kota); // "Bandung" — IKUT BERUBAH!Deep Copy dengan structuredClone
Untuk menyalin objek secara mendalam (semua level):
const user = {
nama: "Budi",
alamat: {
kota: "Jakarta",
kodePos: "12345"
}
};
const salinanDalam = structuredClone(user);
salinanDalam.alamat.kota = "Bandung";
console.log(user.alamat.kota); // "Jakarta" — AMAN!
structuredCloneadalah fitur modern (tersedia di Node.js 17+ dan browser modern). Untuk kasus sederhana, spread{...obj}sudah cukup.
const original = {
nama: "Laptop",
spek: {
ram: 8,
storage: 256
}
};
// Buat salinan DEEP dari original
// Ubah ram di salinan jadi 16
// Pastikan original.spek.ram tetap 83.3 Garbage Collection (Pengumpulan Sampah)
Konsep Dasar
JavaScript punya garbage collector — sistem otomatis yang menghapus data dari memori kalau sudah tidak dipakai.
Aturan utama: Objek yang masih bisa "dijangkau" (reachable) dari kode kita, tetap hidup di memori. Kalau tidak ada yang mereferensikan lagi, dia dihapus.
let user = { nama: "Budi" };
// Objek { nama: "Budi" } bisa dijangkau lewat variabel 'user'
user = null;
// Sekarang tidak ada yang mereferensikan objek tadi
// Garbage collector akan menghapusnya dari memoriBayangkan memori itu gudang. Garbage collector itu petugas kebersihan yang rutin cek: "Barang ini masih ada yang pakai? Kalau tidak, buang."
Kapan Objek Tetap Hidup?
let user = { nama: "Budi" };
let admin = user; // dua referensi ke objek yang sama
user = null; // satu referensi hilang
// Objek MASIH hidup karena 'admin' masih mereferensikan
console.log(admin.nama); // "Budi"Kenapa Perlu Tahu Ini?
Sebagai pemula, kamu tidak perlu mengatur garbage collection secara manual. Tapi penting tahu:
- Jangan simpan referensi ke objek besar yang sudah tidak dipakai
- Set ke
nullkalau sudah selesai dengan objek besar - Memory leak terjadi kalau objek "terjebak" — masih direferensikan padahal sudah tidak dibutuhkan
let a = { data: "penting" };
let b = a;
let c = b;
a = null;
b = null;
// Pertanyaan: Apakah objek { data: "penting" } masih ada di memori?
// Kenapa?3.4 Method Objek dan "this"
Objek Bisa Punya Fungsi!
Di dunia nyata, objek tidak cuma punya data — mereka juga bisa melakukan sesuatu. User bisa login, mobil bisa jalan, dll.
Fungsi yang ada di dalam objek disebut method:
const user = {
nama: "Budi",
umur: 25,
// Ini method
spiHalo() {
console.log("Halo!");
}
};
user.spiHalo(); // "Halo!"Keyword "this"
Bagaimana method mengakses data objeknya sendiri? Pakai this:
const user = {
nama: "Budi",
umur: 25,
perkenalan() {
console.log(`Halo, nama saya ${this.nama}, umur ${this.umur} tahun`);
}
};
user.perkenalan(); // "Halo, nama saya Budi, umur 25 tahun"this = "objek yang memanggil method ini". Saat user.perkenalan() dipanggil, this merujuk ke user.
Kenapa Tidak Langsung Pakai Nama Variabel?
const user = {
nama: "Budi",
perkenalan() {
// Ini BISA tapi BERBAHAYA:
console.log(user.nama);
}
};
const admin = user;
user = null; // Ups!
admin.perkenalan(); // ERROR! user sudah nullKalau pakai this.nama, kode tetap aman meskipun variabel asli dihapus.
"this" Tidak Terikat (Unbound)
Di JavaScript, this ditentukan saat pemanggilan, bukan saat penulisan:
function spiHalo() {
console.log(this.nama);
}
const user1 = { nama: "Budi", spiHalo };
const user2 = { nama: "Andi", spiHalo };
user1.spiHalo(); // "Budi" — this = user1
user2.spiHalo(); // "Andi" — this = user2⚠️ Jebakan: Arrow Function Tidak Punya "this"
Arrow function tidak punya this sendiri. Dia "pinjam" dari fungsi luar:
const user = {
nama: "Budi",
// SALAH — arrow function tidak punya this sendiri
spiHalo: () => {
console.log(this.nama); // undefined!
},
// BENAR — pakai function biasa atau shorthand
spiHalo2() {
console.log(this.nama); // "Budi"
}
};Aturan simpel: Untuk method objek, SELALU pakai shorthand namaMethod() {} atau function. Jangan arrow function.
Method Chaining
Trik keren: method yang mengembalikan this bisa dipanggil berantai:
const kalkulator = {
nilai: 0,
tambah(n) {
this.nilai += n;
return this; // kunci chaining!
},
kali(n) {
this.nilai *= n;
return this;
},
tampilkan() {
console.log(this.nilai);
return this;
}
};
kalkulator.tambah(5).kali(3).tampilkan(); // 15Buat objek keranjang dengan:
- Properti
items(array kosong) - Method
tambah(namaBarang)— push ke items, returnthis - Method
hapus(namaBarang)— hapus dari items, returnthis - Method
tampilkan()— console.log semua items
Gunakan chaining: keranjang.tambah("Apel").tambah("Jeruk").hapus("Apel").tampilkan()
3.5 Constructor dan Operator "new"
Masalah: Membuat Banyak Objek Serupa
Kalau mau bikin 10 user, masa harus tulis objek literal 10 kali?
// Capek kalau harus begini terus:
const user1 = { nama: "Budi", umur: 25 };
const user2 = { nama: "Andi", umur: 30 };
const user3 = { nama: "Cici", umur: 22 };
// ...Solusi: Constructor Function
Constructor function = "cetakan" untuk membuat objek:
function User(nama, umur) {
this.nama = nama;
this.umur = umur;
this.isAdmin = false;
}
const user1 = new User("Budi", 25);
const user2 = new User("Andi", 30);
const user3 = new User("Cici", 22);
console.log(user1); // { nama: "Budi", umur: 25, isAdmin: false }
console.log(user2); // { nama: "Andi", umur: 30, isAdmin: false }Aturan Constructor:
- Nama diawali huruf kapital (konvensi, bukan wajib)
- Dipanggil dengan
new
Apa yang Terjadi Saat new Dipanggil?
function User(nama) {
// 1. JavaScript bikin objek kosong: this = {}
// 2. Fungsi dijalankan, mengisi this
this.nama = nama;
this.isAdmin = false;
// 3. this dikembalikan secara otomatis
}
// Jadi new User("Budi") menghasilkan:
// { nama: "Budi", isAdmin: false }Method di Constructor
function User(nama, umur) {
this.nama = nama;
this.umur = umur;
this.perkenalan = function() {
console.log(`Halo, saya ${this.nama}`);
};
}
const budi = new User("Budi", 25);
budi.perkenalan(); // "Halo, saya Budi"⚠️ Jebakan: Lupa new
Kalau lupa pakai new, this tidak merujuk ke objek baru — hasilnya undefined (strict mode) atau bug aneh:
function User(nama) {
this.nama = nama;
}
// BENAR:
const user1 = new User("Budi");
console.log(user1.nama); // "Budi"
// SALAH (lupa new):
const user2 = User("Budi"); // undefined!
// Di non-strict mode, malah "mencemari" objek globalKapan Pakai Constructor vs Object Literal?
| Situasi | Pakai |
|---|---|
| Objek unik, sekali pakai | Object literal {} |
| Banyak objek dengan struktur sama | Constructor function |
| Nanti (Bab 8) | Class (versi modern constructor) |
Buat constructor Handphone(merk, harga, tahunRilis) yang:
- Menyimpan ketiga parameter sebagai properti
- Punya method
deskripsi()yang return string: "Handphone [merk], harga Rp[harga], rilis tahun [tahunRilis]" - Buat 3 instance handphone berbeda dan panggil
deskripsi()masing-masing
3.6 Optional Chaining (?.)
Masalah: Akses Properti yang Mungkin Tidak Ada
const user = {}; // user tanpa alamat
// Ini ERROR:
// console.log(user.alamat.kota);
// TypeError: Cannot read properties of undefined
// Cara lama (ribet):
console.log(user.alamat ? user.alamat.kota : undefined);Solusi: Optional Chaining ?.
const user = {};
console.log(user?.alamat?.kota); // undefined (TANPA error!)?. artinya: "Kalau bagian sebelum ?. ada (bukan null/undefined), lanjut. Kalau tidak ada, berhenti dan kembalikan undefined."
Contoh Praktis
const user1 = {
nama: "Budi",
alamat: {
kota: "Jakarta",
kodePos: "12345"
}
};
const user2 = {
nama: "Andi"
// tidak punya alamat
};
console.log(user1?.alamat?.kota); // "Jakarta"
console.log(user2?.alamat?.kota); // undefined (aman!)Varian Lain
const user = {
nama: "Budi",
admin: null
};
// ?.() — panggil method yang mungkin tidak ada
user.admin?.(); // tidak error, cuma undefined
// ?.[] — akses properti bracket yang mungkin tidak ada
const kunci = "nama";
console.log(user?.[kunci]); // "Budi"⚠️ Jebakan: Jangan Overuse!
// SALAH — user HARUS ada (ini bug kalau null)
user?.nama;
// BENAR — alamat BOLEH tidak ada
user.alamat?.kota;Pakai ?. hanya di tempat yang memang boleh kosong. Jangan pakai di mana-mana — nanti bug tersembunyi.
const toko = {
nama: "Toko ABC",
cabang: {
jakarta: {
alamat: "Jl. Sudirman No. 1",
manager: { nama: "Budi" }
}
}
};
// Akses nama manager cabang "jakarta" — AMAN
// Akses nama manager cabang "bandung" — AMAN (undefined, bukan error)
// Akses telepon manager cabang "jakarta" — AMAN (undefined, bukan error)3.7 Tipe Symbol
Apa Itu Symbol?
Symbol adalah tipe primitif yang menghasilkan identifier unik. Setiap Symbol yang dibuat dijamin berbeda, bahkan kalau deskripsinya sama.
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false! Selalu unikKenapa Perlu Symbol?
Bayangkan kamu pakai objek dari library orang lain. Kamu mau tambah properti, tapi takut bentrok dengan properti yang sudah ada:
// Objek dari library lain
const user = { nama: "Budi", id: 123 };
// BAHAYA — kalau library juga pakai "id":
user.id = 456; // Menimpa id asli!
// AMAN — pakai Symbol:
const myId = Symbol("id");
user[myId] = 456; // Tidak bentrok!
console.log(user.id); // 123 (asli, aman)
console.log(user[myId]); // 456 (punya kita)Symbol Tersembunyi dari for...in
const id = Symbol("id");
const user = {
nama: "Budi",
umur: 25,
[id]: 123
};
for (let kunci in user) {
console.log(kunci); // "nama", "umur" — Symbol tidak muncul!
}
// Tapi masih bisa diakses langsung:
console.log(user[id]); // 123Kapan Pakai Symbol?
Jujur, sebagai pemula kamu jarang perlu bikin Symbol sendiri. Tapi penting tahu karena:
- JavaScript internal pakai banyak Symbol (
Symbol.iterator,Symbol.toPrimitive, dll) - Library besar pakai Symbol untuk "hidden properties"
- Nanti di bab lanjutan (iterator, class) kamu akan ketemu Symbol lagi
Global Symbol
Kalau mau Symbol yang sama di berbagai tempat:
// Di file A:
const id = Symbol.for("userId");
// Di file B (Symbol yang SAMA):
const idLagi = Symbol.for("userId");
console.log(id === idLagi); // true!// Buat Symbol bernama "rahasia"
// Tambahkan ke objek user sebagai properti dengan nilai "kode-xyz"
// Buktikan bahwa for...in TIDAK menampilkan properti Symbol
// Tapi kamu tetap bisa mengaksesnya langsung3.8 Konversi Objek ke Primitif
Kapan Objek Dikonversi?
Saat objek dipakai di konteks yang butuh primitif:
const user = { nama: "Budi" };
// String context:
alert(user); // "[object Object]" — default jelek
// Number context:
const num = +user; // NaN
// Perbandingan:
console.log(user > 0); // falseTiga "Hint" Konversi
JavaScript memberi "hint" ke objek tentang tipe apa yang diharapkan:
- "string" — saat butuh string (misal
alert(obj)) - "number" — saat butuh angka (misal
+obj, perbandingan) - "default" — saat operator ambigu (misal
obj + "")
Symbol.toPrimitive
Cara paling modern untuk mengontrol konversi:
const user = {
nama: "Budi",
uang: 1000,
[Symbol.toPrimitive](hint) {
if (hint === "string") {
return `User: ${this.nama}`;
}
if (hint === "number") {
return this.uang;
}
// default
return this.uang;
}
};
console.log(`${user}`); // "User: Budi" (hint: string)
console.log(+user); // 1000 (hint: number)
console.log(user + 500); // 1500 (hint: default)Cara Lama: toString dan valueOf
const user = {
nama: "Budi",
uang: 1000,
toString() {
return `User: ${this.nama}`;
},
valueOf() {
return this.uang;
}
};
console.log(String(user)); // "User: Budi"
console.log(+user); // 1000Kapan Perlu Ini?
Sebagai pemula, kamu jarang perlu override konversi. Tapi penting tahu:
- Kenapa
alert(obj)menampilkan[object Object] - Bagaimana library seperti Moment.js bisa bikin
+datemenghasilkan timestamp - Nanti di class, kamu bisa bikin objek yang "pintar" saat dikonversi
// Buat objek "produk" dengan nama dan harga
// Implementasikan Symbol.toPrimitive sehingga:
// - String(produk) → "Produk: [nama]"
// - +produk → harga (number)
// - produk + 100 → harga + 100Ringkasan Bab 3
| Konsep | Poin Kunci |
|---|---|
| Objek | Kumpulan key-value, akses via dot/bracket |
| Referensi | Objek disalin by reference, bukan by value |
| Garbage Collection | Otomatis hapus objek yang unreachable |
| Method & this | Fungsi di objek, this = pemanggil |
| Constructor | Cetakan objek, pakai new + huruf kapital |
| Optional Chaining | ?. untuk akses aman properti nested |
| Symbol | Identifier unik, tersembunyi dari for...in |
| Konversi Primitif | Symbol.toPrimitive, toString, valueOf |
Next: Bab 4 — Tipe Data (Array, Map, Set, dan lainnya)
Sudah paham materi ini?
Tandai sebagai selesai untuk melacak progress-mu.