Volume 2

Q114: Proxy and Reflect

Difficulty: SeniorFrequency: MediumAnswer time: 8-12 minutes

What Interviewers Want To Evaluate

This question checks whether you understand JavaScript metaprogramming. Interviewers want proxies, traps, Reflect, property interception, validation, observability, reactivity, invariants, and performance trade-offs.

Senior answers should know when proxies are useful and when they make code too magical.

Short Interview Answer

A Proxy wraps a target object and intercepts operations like property get, set, delete, function call, and construction through traps. Reflect provides standard methods that mirror many object operations, making it useful inside proxy traps to preserve default behavior. Proxies are powerful for validation, reactivity, logging, and virtualization, but they can hurt readability, debugging, and performance if overused.

Detailed Interview Answer

A proxy lets you customize fundamental object operations.

const target = {
  name: "Asha",
};

const proxy = new Proxy(target, {
  get(object, property, receiver) {
    console.log(`Reading ${String(property)}`);
    return Reflect.get(object, property, receiver);
  },
});

console.log(proxy.name);

The get trap runs when a property is read.

Common Traps

Proxy handlers can define traps for many operations.

Common examples:

get
set
has
deleteProperty
ownKeys
getOwnPropertyDescriptor
apply
construct

Each trap intercepts a specific kind of operation.

Reflect

Reflect exposes object operations as functions.

Reflect.get(object, property, receiver);
Reflect.set(object, property, value, receiver);
Reflect.has(object, property);
Reflect.deleteProperty(object, property);

Inside proxy traps, Reflect is the clean way to delegate to default behavior.

Validation Example

const user = new Proxy(
  {},
  {
    set(target, property, value) {
      if (property === "age" && value < 0) {
        throw new Error("Age cannot be negative");
      }

      return Reflect.set(target, property, value);
    },
  },
);

user.age = 30;

The set trap can enforce rules before storing data.

Reactivity Example

Reactive libraries can use proxies to observe reads and writes.

function reactive(target, onChange) {
  return new Proxy(target, {
    set(object, property, value) {
      const result = Reflect.set(object, property, value);
      onChange(property, value);
      return result;
    },
  });
}

This is a simplified version of a larger idea used in some state systems.

Virtual Properties

Proxies can expose computed or virtual behavior.

const config = new Proxy(
  { apiUrl: "/api" },
  {
    get(target, property) {
      if (property === "isProduction") {
        return process.env.NODE_ENV === "production";
      }

      return Reflect.get(target, property);
    },
  },
);

Use this carefully because hidden behavior can surprise maintainers.

Function Proxies

The apply trap intercepts function calls.

function sum(a, b) {
  return a + b;
}

const tracedSum = new Proxy(sum, {
  apply(target, thisArg, args) {
    console.log("calling sum", args);
    return Reflect.apply(target, thisArg, args);
  },
});

This can support tracing, metrics, or permission checks around function calls.

Constructor Proxies

The construct trap intercepts new.

class Service {}

const TracedService = new Proxy(Service, {
  construct(target, args, newTarget) {
    console.log("creating service");
    return Reflect.construct(target, args, newTarget);
  },
});

This is less common in application code but appears in frameworks and libraries.

Invariants

Proxy traps must respect certain language invariants.

For example, a proxy cannot report impossible behavior for non-configurable properties.

If a trap violates invariants, JavaScript throws a TypeError.

This protects core object assumptions.

Performance Considerations

Proxies can be slower than plain property access because the engine cannot optimize them in the same way.

This does not mean proxies are always bad. It means they should be used where the abstraction value is worth the runtime and debugging cost.

Common Mistakes

A common mistake is returning true from set without actually setting the value.

Another mistake is forgetting the receiver argument in Reflect.get and Reflect.set, which can matter for getters, setters, and inheritance.

Senior Trade-Offs

Use proxies for framework-level behavior, debugging wrappers, validation boundaries, and reactive state abstractions.

Avoid them for ordinary business logic where explicit functions are easier to understand.

Code or Design Example

function createRequiredConfig(config) {
  return new Proxy(config, {
    get(target, property, receiver) {
      if (!(property in target)) {
        throw new Error(`Missing config: ${String(property)}`);
      }

      return Reflect.get(target, property, receiver);
    },
  });
}

This can fail fast when required configuration is missing.

Debugging Workflow

When proxy behavior is confusing:

check which operation triggers which trap
delegate with Reflect when default behavior is needed
check receiver behavior for getters and setters
check non-configurable property invariants
check stack traces for hidden proxy calls
benchmark if used in hot paths
consider replacing with explicit functions

Interview Framing

Define proxy as an interception wrapper. Explain Reflect as the standard way to perform default object operations. Then give a practical validation or reactivity example.

Revision Notes

Proxy intercepts object operations through traps. Reflect mirrors object operations and is commonly used to preserve default behavior inside traps.

Key Takeaways

Proxies are powerful metaprogramming tools, but they should be used with restraint because hidden behavior can make systems harder to debug.

Follow-Up Questions

  1. What is a proxy?
  2. What is a proxy trap?
  3. Why is Reflect useful inside traps?
  4. What does the get trap intercept?
  5. What does the set trap return?
  6. What is the apply trap?
  7. What is the construct trap?
  8. What are proxy invariants?
  9. Why can proxies affect performance?
  10. When should you avoid proxies?

How I Would Answer This In A Real Interview

I would say a proxy wraps an object and intercepts operations through traps. I would use Reflect inside the trap to preserve normal behavior, then discuss validation, reactivity, invariants, and why proxies should usually live in libraries rather than everyday feature code.