Suggest an editImprove this articleRefine the answer for “Why is Reflect needed together with Proxy?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`Reflect`** is needed together with **`Proxy`** because it provides functional counterparts to all the language's basic operations that `Proxy` can intercept, letting you safely call the "default behavior" inside a trap without breaking JS semantics. **Key point:** without `Reflect`, plain `target[prop]` in a `get` trap can run a prototype getter with the wrong `this`, while `Reflect.get(target, prop, receiver)` does it correctly.Shown above the full answer for quick recall.Answer (EN)Image## The problem before Reflect existed Before ES6, there was **no way at all** to intercept operations on an object. With the introduction of `Proxy` this became possible, but it immediately raised another problem: > How do you invoke the "default behavior" after intercepting an operation? For example, you want to log property access, but **not break** the object's behavior: ```javascript const user = { name: "Tim" }; const proxy = new Proxy(user, { get(target, prop, receiver) { console.log(`Reading property "${prop}"`); return target[prop]; // works, but not always correctly } }); ``` This is fine so far, but if: - the property is **on the prototype**, - or it's a **getter**, - or **inheritance** is involved, then plain `target[prop]` can behave **differently** from regular `obj.prop`. --- ## The solution: Reflect To keep `Proxy` traps from breaking JS's normal behavior, `Reflect` was introduced. `Reflect` provides **functional counterparts to all the language's basic operations** that `Proxy` can intercept. For example: ```javascript const proxy = new Proxy(user, { get(target, prop, receiver) { console.log(`Reading "${prop}"`); // a safe call to the default behavior: return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { console.log(`Writing "${prop}" = ${value}`); return Reflect.set(target, prop, value, receiver); } }); ``` Now the proxy behaves **exactly like the original object**, just with extra logic added. --- ## Why you can't just use `target[prop]` Here's an example where the behavior **breaks** without Reflect ```javascript const proto = { get name() { console.log("Getter from the prototype"); return "Alex"; } }; const obj = Object.create(proto); const proxy = new Proxy(obj, { get(target, prop) { console.log("Intercepting get"); return target[prop]; // the getter runs with the wrong this } }); console.log(proxy.name); ``` Result: ```javascript Intercepting get Getter from the prototype ``` but inside the getter, `this` will refer to `target`, not `proxy`. --- The fix, using `Reflect.get`: ```javascript const proxy = new Proxy(obj, { get(target, prop, receiver) { console.log("Intercepting get"); return Reflect.get(target, prop, receiver); // correct } }); console.log(proxy.name); // Intercepting get // Getter from the prototype ``` Now `this` inside the getter correctly points to `proxy`. --- ## A one-to-one relationship Every **`Proxy` trap** has a **matching `Reflect` method** that performs the default behavior: | Proxy trap | Reflect method | What it does | |---|---|---| | `get` | `Reflect.get()` | Reads a property | | `set` | `Reflect.set()` | Sets a value | | `has` | `Reflect.has()` | Checks `prop in obj` | | `deleteProperty` | `Reflect.deleteProperty()` | Deletes a property | | `ownKeys` | `Reflect.ownKeys()` | Gets all keys | | `getOwnPropertyDescriptor` | `Reflect.getOwnPropertyDescriptor()` | Gets a descriptor | | `defineProperty` | `Reflect.defineProperty()` | Defines a property | | `getPrototypeOf` | `Reflect.getPrototypeOf()` | Gets the prototype | | `setPrototypeOf` | `Reflect.setPrototypeOf()` | Changes the prototype | | `isExtensible` | `Reflect.isExtensible()` | Checks extensibility | | `preventExtensions` | `Reflect.preventExtensions()` | Prevents extension | | `apply` | `Reflect.apply()` | Calls a function | | `construct` | `Reflect.construct()` | Calls via `new` | So in every `Proxy` trap you can simply add your own logic and delegate the default operation to `Reflect`. --- ## Example: logging every operation without breaking the logic ```javascript const user = { name: "Tim" }; const proxy = new Proxy(user, { get(target, prop, receiver) { console.log(`GET ${prop}`); return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { console.log(`SET ${prop} = ${value}`); return Reflect.set(target, prop, value, receiver); }, deleteProperty(target, prop) { console.log(`DELETE ${prop}`); return Reflect.deleteProperty(target, prop); } }); proxy.name; // GET name proxy.age = 30; // SET age = 30 delete proxy.age;// DELETE age ``` Without `Reflect` you'd have to manually emulate the language's behavior (which is difficult and unsafe). --- ## Additional advantages of `Reflect` 1. Its methods **return true/false** instead of throwing errors. Convenient for checking whether an operation succeeded. ```javascript Reflect.defineProperty({}, 'x', { value: 1 }); // true ``` 2. You can **programmatically** perform operations that are normally expressed with operators (`delete`, `in`, `new`, calling a function). ```javascript Reflect.apply(Math.max, null, [1, 2, 3]); // 3 Reflect.construct(Date, [2025, 0, 1]); // equivalent to new Date(2025, 0, 1) ``` 3. You build a `Proxy`, safely delegate through `Reflect`, and never break the language. --- ## Summary | What | Role | |---|---| | `Proxy` | Intercepts operations on an object | | `Reflect` | Lets you perform the "original" operation inside a trap | | **Why together** | To extend or modify an object's behavior **without breaking standard JS semantics** | | **Advantage** | Predictable code that's compatible with inheritance, getters/setters, and built-in objects |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.