Proxy adalah pembungkus object yang menangkap tiap operasi ke object itu, misalnya membaca atau mengubah properti, sebelum operasinya sampai ke object aslinya. Di situ kamu bisa mencatat, mengecek, lalu meneruskan atau menolak. Mirip satpam di depan pintu: semua yang masuk lewat dia dulu.
🧪 Tebakan cepat: object
{ nama: 'Budi' }gak punya propertiumur. Apakah membacaumurlewat Proxy pasti menghasilkanundefined? Tebak dulu, jawabannya ada di bagian "Trapget: menangkap pembacaan".
Proxy pertama: trap set buat validasi
const target = { umur: 20 }
const siswa = new Proxy(target, {
set(obj, prop, value) {
if (typeof value !== 'number' || value <= 0) {
throw new Error('Umur harus angka lebih dari 0')
}
obj[prop] = value
return true
}
})
siswa.umur = 25 // tersimpan
siswa.umur = -5 // Error: Umur harus angka lebih dari 0
new Proxy(target, handler)bikin Proxy.targetadalah object aslinya,handleradalah object berisi trap.- Trap adalah method di handler yang menangkap satu jenis operasi.
setmenangkap tiap penulisan properti, misalnyasiswa.umur = 25. - Trap
setmenerimaobj(object asli),prop(nama propertinya, di sini'umur') danvalue(nilai barunya,25). throw new Error(...)menolak: penulisannya berhenti dan nilai lama tetap.obj[prop] = valuemenyimpan nilainya ke object asli. Tanpa baris ini, nilainya gak pernah tersimpan.return truemelapor bahwa penyimpanannya berhasil. Trapsetharus mengembalikantruekalau berhasil. Kalau gak me-return apa pun, operasinya dianggap gagal.
Hasilnya, siswa.umur jadi 25, sedangkan -5 ditolak dengan Error dan umurnya tetap 25. siswa.umur = 'abc' juga ditolak, karena tipenya bukan number. Satu catatan: Proxy cuma menjaga operasi yang lewat dia. target.umur = -5, langsung ke object aslinya, gak dicek sama sekali.
Trap get: menangkap pembacaan
const p = new Proxy({ nama: 'Budi' }, {
get(obj, prop) {
return prop in obj ? obj[prop] : 'tidak ada'
}
})
console.log(p.nama) // Budi
console.log(p.umur) // tidak ada
get(obj, prop)jalan tiap kali sebuah properti dibaca.prop in objmengecek apakah properti itu ada di object.- Apa pun yang di-return trap jadi hasil bacaannya.
Jawaban tebakan: gak pasti. Tanpa Proxy, p.umur memang undefined. Dengan trap ini, hasilnya 'tidak ada', karena trap yang memutuskan.
Reflect: meneruskan operasi apa adanya
Reflect berisi method dengan nama yang sama dengan trap, dan tiap method melakukan operasi bawaannya:
const handler = {
get(obj, prop) {
console.log(`Membaca ${prop}`)
return Reflect.get(obj, prop)
},
set(obj, prop, value) {
console.log(`Menulis ${prop} = ${value}`)
return Reflect.set(obj, prop, value)
}
}
const user = new Proxy({}, handler)
user.nama = 'Budi' // Menulis nama = Budi
console.log(user.nama) // Membaca nama, lalu Budi
Reflect.get(obj, prop)sama denganobj[prop].Reflect.set(obj, prop, value)sama denganobj[prop] = value, dan mengembalikantruekalau berhasil. Jadiobj[prop] = valueplusreturn truebisa disingkatreturn Reflect.set(obj, prop, value).Reflect.set(proxy, 'b', 7)yang dipanggil ke Proxy mengembalikan apa yang di-return trapset. Trap tanpareturn truebikin hasilnyafalse.
Selain get dan set, ada trap lain kayak has (untuk in) dan deleteProperty (untuk delete).
⚠️ Jebakan yang sering ketemu
- Trap
settanpareturn true. Penyimpanannya dilaporkan gagal, dan di strict mode itu jadi TypeError. - Lupa menyimpan nilainya. Trap yang cuma mengecek lalu
return truebikin nilainya gak pernah masuk ke object. - Cuma mengecek
value < 0. Angka 0 lolos. Kalau aturannya "lebih dari 0", tolakvalue <= 0. - Lupa mengecek tipe.
'abc' <= 0hasilnyafalse, jadi teks lolos kalau gak adatypeof value !== 'number'.
TL;DR: new Proxy(target, handler) membungkus object, dan trap di handler menangkap operasinya. Trap set(obj, prop, value) menangkap penulisan: tolak dengan throw new Error(...), atau simpan dengan obj[prop] = value lalu return true. Trap get(obj, prop) menangkap pembacaan, dan yang di-return-nya jadi hasilnya. Reflect.get dan Reflect.set menjalankan operasi bawaannya, jadi trap bisa meneruskan dengan return Reflect.set(obj, prop, value).