Q36 of 40 · JavaScript

What is the `Reflect` API, and how does it complement `Proxy`?

JavaScriptSeniorjavascriptreflectproxymetaprogramminges6

Short answer

Short answer: `Reflect` provides static methods mirroring Proxy traps, allowing clean forwarding to the target's default behaviour inside trap handlers. Without `Reflect`, forwarding requires `target[prop]` which can miss receiver-binding and descriptor edge cases. `Reflect` methods also return success flags instead of throwing on failure.

Detail

Reflect is a built-in object (not a constructor) introduced alongside Proxy in ES6. Its methods correspond exactly to Proxy trap names and provide the default behaviour for each operation.

Why it exists: Inside a Proxy trap, you often want to call through to the original behaviour with correct semantics. Using target[prop] directly can break:

  • Receiver binding: For accessor properties with getters, target[prop] calls the getter with this = target, but Reflect.get(target, prop, receiver) passes the Proxy as this, which is often what inherited getters need.
  • Success signalling: Reflect.set() returns true/false instead of throwing on non-writable properties, making error handling in set traps cleaner.

Reflect methods: Reflect.get, Reflect.set, Reflect.has, Reflect.deleteProperty, Reflect.apply, Reflect.construct, Reflect.ownKeys, and more — one for each Proxy trap.

Testing use: Reflect is used in advanced mock frameworks and assertion libraries to intercept and verify operations. Reflect.apply provides a safe way to call a function with a dynamic argument list, similar to Function.prototype.apply but without needing a method reference.

// EXAMPLE

// Without Reflect — receiver issue
const handler1 = {
  get(target, prop) {
    return target[prop]; // wrong: 'this' in getter = target, not proxy
  }
};

// With Reflect — correct receiver
const handler2 = {
  get(target, prop, receiver) {
    console.log(`get: ${prop}`);
    return Reflect.get(target, prop, receiver); // correct
  },
  set(target, prop, value, receiver) {
    console.log(`set: ${prop} = ${value}`);
    return Reflect.set(target, prop, value, receiver); // returns bool
  }
};

const proxy = new Proxy({ x: 1 }, handler2);
proxy.x;      // logs "get: x" → 1
proxy.y = 2;  // logs "set: y = 2"

// Reflect.apply — like Function.prototype.apply but safer
function sum(...args) { return args.reduce((a, b) => a + b, 0); }
Reflect.apply(sum, null, [1, 2, 3]); // 6

// WHAT INTERVIEWERS LOOK FOR

Understanding that Reflect methods are the default behaviour counterpart to Proxy traps. The receiver-binding issue that `target[prop]` doesn't handle. Success-flag semantics of Reflect.set. This is an advanced topic — knowing it marks senior-level metaprogramming fluency.

// COMMON PITFALL

Using `target[prop]` instead of `Reflect.get(target, prop, receiver)` in a get trap — this breaks inherited accessor properties that check `this` identity.