Web Development

JavaScript Proxy & Reflect: Metaprogramming Modern

Kuasai Proxy dan Reflect API untuk membangun reactive objects, validasi otomatis, logging, dan teknik metaprogramming tingkat lanjut di JavaScript

1. Pengenalan Proxy & Reflect

Proxy adalah fitur ES6 yang memungkinkan Anda membuat "pembungkus" (wrapper) di sekitar objek, array, atau fungsi. Proxy bisa menangkap dan mengubah perilaku dasar dari operasi pada objek — seperti membaca properti, menulis nilai, memanggil fungsi, dan lain-lain.

Reflect adalah API built-in yang menyediakan metode-metode untuk melakukan operasi dasar pada objek (get, set, has, deleteProperty, dll). Reflect dirancang untuk digunakan bersama Proxy agar handler bisa meneruskan operasi ke target secara default.

Mengapa Proxy Penting?

Fitur Penjelasan
Intercept OperasiMenangkap get, set, delete, has, dan operasi lainnya
ValidasiValidasi data secara otomatis sebelum disimpan
Logging & DebugTrack semua akses dan perubahan properti
Reactive SystemMembangun sistem reaktif seperti Vue.js 3
Default ValuesMenyediakan default untuk properti yang tidak ada
Access ControlMembatasi akses ke properti tertentu (private/readonly)

Browser Support

💡 Kompatibilitas

Proxy dan Reflect didukung di semua browser modern (Chrome 49+, Firefox 18+, Safari 10+, Edge 12+). Proxy tidak bisa di-polyfill karena ini adalah fitur bahasa tingkat rendah. Jika Anda perlu support IE11, Proxy bukan pilihan.

Syntax Dasar Proxy

JavaScript — Proxy Dasar
// Syntax: new Proxy(target, handler)
// target  = objek yang ingin dibungkus
// handler = objek yang berisi traps (perangkap)

const target = {
    nama: 'Beebane',
    umur: 25
};

const handler = {}; // Handler kosong — tidak ada traps

const proxy = new Proxy(target, handler);

// Proxy bertindak persis seperti target
console.log(proxy.nama);  // → 'Beebane'
console.log(proxy.umur);  // → 25

// Operasi pada proxy mempengaruhi target
proxy.kota = 'Jakarta';
console.log(target.kota); // → 'Jakarta'

2. Cara Kerja Proxy

Proxy bekerja dengan menangkap operasi dasar (fundamental operations) pada objek target. Setiap operasi dasar memiliki trap (perangkap) yang bisa Anda definisikan di handler.

Diagram: Cara Proxy Bekerja
  Kode Anda → Proxy → Handler (Traps?) → Target
                  ↓
              Jika ada trap:
              Jalankan logika kustom
                  ↓
              Jika tidak ada trap:
              Jalankan operasi default (via Reflect)

  Contoh:
  proxy.nama  →  Proxy  →  handler.get() ada?
                                    ↓
                          Ya → jalankan handler.get()
                          Tidak → Reflect.get(target, 'nama')

Daftar Lengkap Traps

JavaScript — Semua Trap yang Tersedia
// ===== 13 Trap yang tersedia di Proxy =====

const handler = {
    // Membaca properti          → get(target, prop, receiver)
    get(target, prop, receiver) {},

    // Menulis properti          → set(target, prop, value, receiver)
    set(target, prop, value, receiver) {},

    // Cek 'in' operator         → has(target, prop)
    has(target, prop) {},

    // Hapus properti            → deleteProperty(target, prop)
    deleteProperty(target, prop) {},

    // Object.keys()             → ownKeys(target)
    ownKeys(target) {},

    // Object.getOwnPropertyDescriptor() → getOwnPropertyDescriptor(target, prop)
    getOwnPropertyDescriptor(target, prop) {},

    // Object.defineProperty()   → defineProperty(target, prop, descriptor)
    defineProperty(target, prop, descriptor) {},

    // Object.getPrototypeOf()   → getPrototypeOf(target)
    getPrototypeOf(target) {},

    // Object.setPrototypeOf()   → setPrototypeOf(target, proto)
    setPrototypeOf(target, proto) {},

    // Object.preventExtensions() → preventExtensions(target)
    preventExtensions(target) {},

    // Object.isExtensible()     → isExtensible(target)
    isExtensible(target) {},

    // Fungsi dipanggil           → apply(target, thisArg, args)
    apply(target, thisArg, args) {},

    // new Operator               → construct(target, args, newTarget)
    construct(target, args, newTarget) {}
};
⚠️ Invariant (Aturan Ketat)

Proxy memiliki invariants — aturan ketat yang HARUS dipatuhi oleh trap. Misalnya: trap set harus mengembalikan true/false, trap get untuk properti non-writable non-configurable harus mengembalikan nilai yang sama dengan target. Pelanggaran invariant akan melempar TypeError.

3. Get & Set Traps

Trap get dan set adalah dua trap yang paling sering digunakan. Mereka menangkap operasi pembacaan dan penulisan properti pada objek.

Get Trap — Membaca Properti

JavaScript — Get Trap
// ===== Contoh 1: Default Values =====
const data = { nama: 'Beebane' };

const proxyData = new Proxy(data, {
    get(target, prop, receiver) {
        if (prop in target) {
            return Reflect.get(target, prop, receiver);
        }
        return `Properti '${prop}' tidak ditemukan`;
    }
});

console.log(proxyData.nama);    // → 'Beebane'
console.log(proxyData.umur);    // → "Properti 'umur' tidak ditemukan"

// ===== Contoh 2: Logging / Audit Trail =====
const pengaturan = {
    tema: 'dark',
    bahasa: 'id',
    fontSize: 16
};

const loggedPengaturan = new Proxy(pengaturan, {
    get(target, prop, receiver) {
        console.log(`[GET] Membaca properti: ${prop}`);
        console.log(`[GET] Nilai: ${target[prop]}`);
        return Reflect.get(target, prop, receiver);
    }
});

loggedPengaturan.tema;
// Output:
// [GET] Membaca properti: tema
// [GET] Nilai: dark

// ===== Contoh 3: Nested Proxy (Deep Proxy) =====
function deepProxy(obj, handler) {
    for (const key of Object.keys(obj)) {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            obj[key] = deepProxy(obj[key], handler);
        }
    }
    return new Proxy(obj, handler);
}

const nested = deepProxy(
    { user: { profile: { nama: 'Beebane' } } },
    {
        get(target, prop) {
            console.log(`[DEEP GET] ${prop}`);
            return Reflect.get(target, prop);
        }
    }
);

nested.user.profile.nama;
// [DEEP GET] user
// [DEEP GET] profile
// [DEEP GET] nama

Set Trap — Menulis Properti

JavaScript — Set Trap
// ===== Contoh 1: Type Checking =====
const userProxy = new Proxy({}, {
    set(target, prop, value, receiver) {
        // Validasi tipe berdasarkan nama properti
        if (prop === 'nama' && typeof value !== 'string') {
            throw new TypeError(`'${prop}' harus berupa string`);
        }
        if (prop === 'umur' && typeof value !== 'number') {
            throw new TypeError(`'${prop}' harus berupa number`);
        }
        if (prop === 'umur' && (value < 0 || value > 150)) {
            throw new RangeError(`'${prop}' harus antara 0-150`);
        }

        console.log(`[SET] ${prop} = ${value}`);
        return Reflect.set(target, prop, value, receiver);
    }
});

userProxy.nama = 'Beebane';   // OK → [SET] nama = Beebane
userProxy.umur = 25;          // OK → [SET] umur = 25
// userProxy.umur = -5;       // ❌ RangeError!
// userProxy.nama = 123;      // ❌ TypeError!

// ===== Contoh 2: Readonly Properties =====
const config = new Proxy({ host: 'localhost', port: 3000 }, {
    set(target, prop, value, receiver) {
        // Semua properti menjadi readonly setelah inisialisasi
        console.warn(`[WARN] Properti '${prop}' bersifat readonly!`);
        return false; // Menolak penulisan
    }
});

config.host = 'example.com'; // → [WARN] Properti 'host' bersifat readonly!
console.log(config.host);    // → 'localhost' (tidak berubah!)

4. Has & Delete Traps

Trap has menangkap operator in, sedangkan deleteProperty menangkap operasi delete.

JavaScript — Has & Delete Traps
// ===== Has Trap: Menyembunyikan Properti =====
const rahasia = {
    nama: 'Beebane',
    _password: 'rahasia123',
    _apiKey: 'xyz-abc-123'
};

const amanRahasia = new Proxy(rahasia, {
    has(target, prop) {
        // Sembunyikan properti yang diawali underscore
        if (prop.startsWith('_')) {
            console.log(`[HAS] Properti '${prop}' disembunyikan`);
            return false;
        }
        return Reflect.has(target, prop);
    }
});

console.log('nama' in amanRahasia);       // → true
console.log('_password' in amanRahasia);   // → false (disembunyikan!)
console.log('_apiKey' in amanRahasia);     // → false (disembunyikan!)

// ===== Delete Trap: Mencegah Penghapusan =====
const konstanta = new Proxy(
    { API_URL: 'https://api.example.com', VERSION: '2.0' },
    {
        deleteProperty(target, prop) {
            throw new Error(`Tidak bisa menghapus konstanta '${prop}'`);
        }
    }
);

// delete konstanta.API_URL;  // ❌ Error: Tidak bisa menghapus konstanta 'API_URL'

// ===== OwnKeys Trap: Filter Keys =====
const dataUser = {
    id: 1,
    nama: 'Beebane',
    email: 'bee@example.com',
    _token: 'secret-token',
    _session: 'abc123'
};

const filteredProxy = new Proxy(dataUser, {
    ownKeys(target) {
        // Hanya kembalikan key yang BUKAN private
        return Reflect.ownKeys(target).filter(
            key => !key.startsWith('_')
        );
    }
});

console.log(Object.keys(filteredProxy));
// → ['id', 'nama', 'email'] (tanpa _token dan _session)

5. Apply & Construct Traps

Trap apply menangkap pemanggilan fungsi, sedangkan construct menangkap penggunaan new operator.

JavaScript — Apply & Construct Traps
// ===== Apply Trap: Memodifikasi Fungsi =====

// Contoh 1: Memoization (Cache Hasil)
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// Bungkus dengan cache
const cache = new Map();
const cachedFib = new Proxy(fibonacci, {
    apply(target, thisArg, args) {
        const key = args.toString();
        if (cache.has(key)) {
            console.log(`[CACHE HIT] fib(${key})`);
            return cache.get(key);
        }
        console.log(`[COMPUTE] fib(${key})`);
        const result = Reflect.apply(target, thisArg, args);
        cache.set(key, result);
        return result;
    }
});

console.log(cachedFib(10));  // [COMPUTE] → 55
console.log(cachedFib(10));  // [CACHE HIT] → 55

// Contoh 2: Logging Function Calls
function tambah(a, b) { return a + b; }
function kali(a, b) { return a * b; }

function withLogging(fn, name) {
    return new Proxy(fn, {
        apply(target, thisArg, args) {
            console.log(`[CALL] ${name}(${args.join(', ')})`);
            const result = Reflect.apply(target, thisArg, args);
            console.log(`[RETURN] ${name} → ${result}`);
            return result;
        }
    });
}

const loggedTambah = withLogging(tambah, 'tambah');
loggedTambah(5, 3);
// [CALL] tambah(5, 3)
// [RETURN] tambah → 8

// ===== Construct Trap: Memodifikasi new =====
class Orang {
    constructor(nama, umur) {
        this.nama = nama;
        this.umur = umur;
    }
}

const ProxyOrang = new Proxy(Orang, {
    construct(target, args, newTarget) {
        console.log(`[NEW] Membuat instance: ${args.join(', ')}`);
        const instance = Reflect.construct(target, args, newTarget);
        instance.dibuatPada = new Date(); // Tambah properti otomatis
        return instance;
    }
});

const user = new ProxyOrang('Beebane', 25);
console.log(user.nama);       // → 'Beebane'
console.log(user.dibuatPada); // → Date object

6. Reflect API Lengkap

Reflect adalah objek built-in yang menyediakan metode untuk melakukan operasi dasar objek secara terstandarisasi. Sebelum Reflect, operasi ini tersebar di berbagai tempat (Object methods, operator, dll).

JavaScript — Reflect API
// ===== Mengapa Menggunakan Reflect? =====

// 1. Reflect.get(target, prop, receiver)
const obj = { nama: 'Beebane', get info() { return this.nama; } };
const proxy = new Proxy(obj, {
    get(target, prop, receiver) {
        // receiver memastikan 'this' benar di getter
        return Reflect.get(target, prop, receiver);
    }
});
console.log(proxy.info); // → 'Beebane' (benar!)

// 2. Reflect.set(target, prop, value, receiver)
const counter = { _val: 0, set nilai(v) { this._val = v; } };
Reflect.set(counter, 'nilai', 42);
console.log(counter._val); // → 42

// 3. Reflect.has(target, prop) — mirip 'in' operator
console.log(Reflect.has({ a: 1 }, 'a')); // → true
console.log(Reflect.has({ a: 1 }, 'b')); // → false

// 4. Reflect.deleteProperty(target, prop)
const data = { a: 1, b: 2 };
Reflect.deleteProperty(data, 'a');
console.log(data); // → { b: 2 }

// 5. Reflect.ownKeys(target)
const mixed = { a: 1, [Symbol('id')]: 99 };
console.log(Reflect.ownKeys(mixed)); // → ['a', Symbol(id)]

// 6. Reflect.construct(target, args)
class Animal {
    constructor(name) { this.name = name; }
}
const cat = Reflect.construct(Animal, ['Kucing']);
console.log(cat.name); // → 'Kucing'

// 7. Reflect.apply(target, thisArg, args)
function greet(greeting) {
    return `${greeting}, ${this.nama}!`;
}
const result = Reflect.apply(greet, { nama: 'Beebane' }, ['Halo']);
console.log(result); // → 'Halo, Beebane!'

// 8. Reflect.defineProperty(target, prop, descriptor)
const obj2 = {};
Reflect.defineProperty(obj2, 'x', {
    value: 10,
    writable: false,
    enumerable: true,
    configurable: false
});
console.log(obj2.x); // → 10

// 9. Reflect.getPrototypeOf(target) & setPrototypeOf
const proto = { greet() { return 'Hello'; } };
const obj3 = {};
Reflect.setPrototypeOf(obj3, proto);
console.log(obj3.greet()); // → 'Hello'

// 10. Reflect.preventExtensions(target) & isExtensible
const sealed = { a: 1 };
Reflect.preventExtensions(sealed);
console.log(Reflect.isExtensible(sealed)); // → false
💡 Mengapa Reflect Lebih Baik?

Dibandingkan metode Object seperti Object.getOwnPropertyDescriptor(), Reflect methods selalu mengembalikan boolean untuk operasi yang sebelumnya melempar error (seperti defineProperty). Ini membuat kode lebih bersih dan konsisten.

7. Validasi dengan Proxy

Salah satu use case paling populer dari Proxy adalah validasi data. Anda bisa membuat skema validasi yang otomatis mengecek tipe, range, dan format data saat properti diubah.

JavaScript — Schema Validation
// ===== Schema Validator menggunakan Proxy =====
function createValidatedObject(schema) {
    const data = {};

    return new Proxy(data, {
        set(target, prop, value, receiver) {
            // Cek apakah properti ada di schema
            if (!(prop in schema)) {
                throw new Error(`Properti '${prop}' tidak ada dalam schema`);
            }

            const rules = schema[prop];

            // Validasi tipe
            if (rules.type && typeof value !== rules.type) {
                throw new TypeError(
                    `'${prop}' harus bertipe ${rules.type}, diterima: ${typeof value}`
                );
            }

            // Validasi required
            if (rules.required && (value === null || value === undefined)) {
                throw new Error(`'${prop}' wajib diisi`);
            }

            // Validasi min/max untuk number
            if (rules.type === 'number') {
                if (rules.min !== undefined && value < rules.min) {
                    throw new RangeError(`'${prop}' minimal ${rules.min}`);
                }
                if (rules.max !== undefined && value > rules.max) {
                    throw new RangeError(`'${prop}' maksimal ${rules.max}`);
                }
            }

            // Validasi minLength/maxLength untuk string
            if (rules.type === 'string') {
                if (rules.minLength && value.length < rules.minLength) {
                    throw new Error(`'${prop}' minimal ${rules.minLength} karakter`);
                }
                if (rules.maxLength && value.length > rules.maxLength) {
                    throw new Error(`'${prop}' maksimal ${rules.maxLength} karakter`);
                }
            }

            // Validasi pattern (regex)
            if (rules.pattern && !rules.pattern.test(value)) {
                throw new Error(`'${prop}' tidak sesuai format`);
            }

            return Reflect.set(target, prop, value, receiver);
        }
    });
}

// Definisikan schema
const userSchema = {
    nama: { type: 'string', required: true, minLength: 2, maxLength: 50 },
    umur: { type: 'number', required: true, min: 0, max: 150 },
    email: {
        type: 'string',
        required: true,
        pattern: /^[\w.-]+@[\w.-]+\.\w+$/
    }
};

const user = createValidatedObject(userSchema);

user.nama = 'Beebane';        // ✅ OK
user.umur = 25;               // ✅ OK
user.email = 'test@mail.com'; // ✅ OK

// user.nama = 123;            // ❌ TypeError
// user.umur = -1;             // ❌ RangeError
// user.email = 'invalid';     // ❌ Error: format
// user.unknown = 'test';      // ❌ Error: tidak ada dalam schema
JavaScript — Strict Mode Proxy
// ===== Strict Object: Cegah Akses Properti Tak Terduga =====
function strict(obj) {
    return new Proxy(obj, {
        get(target, prop, receiver) {
            if (prop in target) {
                return Reflect.get(target, prop, receiver);
            }
            throw new ReferenceError(
                `Properti '${prop}' tidak ditemukan. ` +
                `Properti yang tersedia: ${Object.keys(target).join(', ')}`
            );
        },
        set(target, prop, value, receiver) {
            if (!(prop in target)) {
                throw new ReferenceError(
                    `Tidak bisa menambah properti baru '${prop}'`
                );
            }
            return Reflect.set(target, prop, value, receiver);
        }
    });
}

const konfig = strict({
    apiUrl: 'https://api.example.com',
    timeout: 5000,
    retries: 3
});

console.log(konfig.apiUrl);   // ✅ OK
// console.log(konfig.url);   // ❌ ReferenceError!

8. Reactive Objects

Proxy adalah fondasi dari sistem reaktif seperti Vue.js 3. Dengan Proxy, Anda bisa mendeteksi perubahan data dan secara otomatis memperbarui UI atau menjalankan efek samping (side effects).

JavaScript — Simple Reactive System
// ===== Reactive System Sederhana =====
function reactive(target) {
    const listeners = new Map(); // prop → Set of callbacks

    function notify(prop) {
        if (listeners.has(prop)) {
            listeners.get(prop).forEach(cb => cb(prop, target[prop]));
        }
    }

    return new Proxy(target, {
        get(target, prop, receiver) {
            // Jika prop adalah method untuk subscribe
            if (prop === '_subscribe') {
                return (propName, callback) => {
                    if (!listeners.has(propName)) {
                        listeners.set(propName, new Set());
                    }
                    listeners.get(propName).add(callback);
                };
            }
            return Reflect.get(target, prop, receiver);
        },
        set(target, prop, value, receiver) {
            const oldValue = target[prop];
            const result = Reflect.set(target, prop, value, receiver);
            if (oldValue !== value) {
                notify(prop);
            }
            return result;
        }
    });
}

// Gunakan reactive
const state = reactive({
    count: 0,
    nama: 'Beebane'
});

// Subscribe ke perubahan
state._subscribe('count', (prop, newVal) => {
    console.log(`[REACT] ${prop} berubah menjadi: ${newVal}`);
});

state._subscribe('nama', (prop, newVal) => {
    console.log(`[REACT] ${prop} berubah menjadi: ${newVal}`);
});

// Trigger reactive
state.count = 1;   // [REACT] count berubah menjadi: 1
state.count = 2;   // [REACT] count berubah menjadi: 2
state.nama = 'BL'; // [REACT] nama berubah menjadi: BL
JavaScript — Computed Properties
// ===== Computed Properties dengan Proxy =====
function computed(target, computeds) {
    return new Proxy(target, {
        get(target, prop, receiver) {
            // Cek apakah properti adalah computed
            if (prop in computeds) {
                return computeds[prop](target);
            }
            return Reflect.get(target, prop, receiver);
        }
    });
}

const data = computed(
    { harga: 100000, pajak: 0.11 },
    {
        totalPajak: (d) => d.harga * d.pajak,
        hargaAkhir: (d) => d.harga + d.harga * d.pajak,
        formatted: (d) => `Rp ${(d.harga + d.harga * d.pajak).toLocaleString('id')}`
    }
);

console.log(data.totalPajak);  // → 11000
console.log(data.hargaAkhir);  // → 111000
console.log(data.formatted);   // → "Rp 111.000"

// Computed otomatis berubah saat data berubah
data.harga = 200000;
console.log(data.hargaAkhir);  // → 222000

9. Use Cases Lanjutan

Negative Array Indexing

JavaScript — Negative Array Index
// Mirip Python: arr[-1] mendapatkan elemen terakhir
function negativeArray(arr) {
    return new Proxy(arr, {
        get(target, prop, receiver) {
            const index = Number(prop);
            if (Number.isInteger(index) && index < 0) {
                return Reflect.get(target, target.length + index, receiver);
            }
            return Reflect.get(target, prop, receiver);
        }
    });
}

const items = negativeArray(['a', 'b', 'c', 'd', 'e']);
console.log(items[-1]);  // → 'e' (elemen terakhir)
console.log(items[-2]);  // → 'd'

Observable (Watch All Changes)

JavaScript — Observable Proxy
// ===== Observable: Watch Semua Perubahan =====
function observable(target, onChange) {
    return new Proxy(target, {
        set(obj, prop, value, receiver) {
            const oldValue = obj[prop];
            const result = Reflect.set(obj, prop, value, receiver);
            if (oldValue !== value) {
                onChange({
                    type: 'set',
                    prop,
                    oldValue,
                    newValue: value
                });
            }
            return result;
        },
        deleteProperty(obj, prop) {
            const oldValue = obj[prop];
            const result = Reflect.deleteProperty(obj, prop);
            onChange({
                type: 'delete',
                prop,
                oldValue
            });
            return result;
        }
    });
}

const state = observable({ count: 0, items: [] }, (change) => {
    console.log('[CHANGE]', change);
});

state.count = 1;
// [CHANGE] { type: 'set', prop: 'count', oldValue: 0, newValue: 1 }

delete state.count;
// [CHANGE] { type: 'delete', prop: 'count', oldValue: 1 }

Revocable Proxy

JavaScript — Revocable Proxy
// ===== Revocable Proxy: Bisa Dinonaktifkan =====
const sensitiveData = { apiKey: 'secret-123', token: 'bearer-abc' };

const { proxy, revoke } = Proxy.revocable(sensitiveData, {
    get(target, prop) {
        console.log(`[ACCESS] ${prop}`);
        return Reflect.get(target, prop);
    }
});

// Bisa diakses
console.log(proxy.apiKey);  // → 'secret-123'

// Revoke (nonaktifkan proxy)
revoke();

// Semua operasi sekarang error!
// proxy.apiKey;  // ❌ TypeError: proxy has been revoked
// proxy.token;   // ❌ TypeError: proxy has been revoked

Proxy untuk Debugging

JavaScript — Debug Helper
// ===== Trace Helper: Log Semua Operasi pada Object =====
function trace(obj, name = 'Object') {
    return new Proxy(obj, {
        get(target, prop, receiver) {
            console.log(`[${name}] GET ${String(prop)}`);
            const value = Reflect.get(target, prop, receiver);
            if (typeof value === 'function') {
                return function(...args) {
                    console.log(`[${name}] CALL ${String(prop)}(${args})`);
                    return Reflect.apply(value, target, args);
                };
            }
            return value;
        },
        set(target, prop, value, receiver) {
            console.log(`[${name}] SET ${String(prop)} = ${value}`);
            return Reflect.set(target, prop, value, receiver);
        }
    });
}

const arr = trace([1, 2, 3], 'Array');
arr.push(4);
// [Array] GET push
// [Array] CALL push(4)
console.log(arr.length);
// [Array] GET length
// → 4

10. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Proxy & Reflect:

Pertanyaan 1: Apa fungsi utama dari new Proxy(target, handler)?

a) Membuat salinan (clone) dari objek target
b) Membungkus objek dan menangkap operasi dasarnya
c) Mengenkripsi semua data dalam objek
d) Mengkonversi objek ke JSON

Pertanyaan 2: Trap apa yang menangkap operasi obj.prop = value?

a) get
b) has
c) set
d) defineProperty

Pertanyaan 3: Mengapa kita menggunakan Reflect.get() di dalam trap handler?

a) Agar kode lebih cepat
b) Untuk meneruskan operasi ke target secara default
c) Untuk menghapus proxy
d) Untuk menambah properti baru

Pertanyaan 4: Apa yang dilakukan Proxy.revocable()?

a) Membuat proxy yang lebih cepat
b) Membuat proxy yang bisa dinonaktifkan setelah dibuat
c) Membuat proxy yang tidak bisa dimodifikasi
d) Membuat proxy dari array

Pertanyaan 5: Framework JavaScript modern mana yang menggunakan Proxy untuk sistem reaktivitasnya?

a) React
b) Angular
c) Vue.js 3
d) jQuery
🔍 Zoom
100%
🎨 Tema