Skip to content
Lesson 3 of 8

Step 1 of 5 · Reading · ~3 min

Learn

Proxy and Memory

Proxy and Reflect

A Proxy wraps an object and lets your code decide what happens when someone reads, writes, deletes or lists its properties. Reflect is the toolbox for doing the default thing from inside such a decision. By the end you can write a proxy that guards, logs or reshapes an object without breaking getters or strict-mode callers.

Target, handler, traps

new Proxy(target, handler) returns an object that forwards every operation to target, except the ones handler overrides. Each override is a trap, a method named after the operation:

OperationTrap
p.x, p[x]get(target, key, receiver)
p.x = vset(target, key, value, receiver)
key in phas(target, key)
delete p.xdeleteProperty(target, key)
Object.keys(p), for...in, JSON.stringify(p)ownKeys(target)
p(...) on a functionapply(target, thisArg, args)
new p(...)construct(target, args, newTarget)

A handler with no traps is a transparent pass-through. Keys arrive as strings or symbols, so a trap that calls string methods on key must check typeof key first.

Reflect does the default, correctly

Reflect has one function per trap (Reflect.get, Reflect.set, Reflect.has, Reflect.ownKeys, ...) that performs the normal operation. Prefer it to target[key] because of the receiver: the object the operation was started on. Look at what a getter does with this:

javascript

A set trap must say whether it worked

set returns a boolean. Returning false (or nothing) means "refused". In sloppy mode the assignment then silently does nothing; in strict mode it throws a TypeError. Class bodies and ES modules are always strict, so a missing return true often shows up only after a refactor.

javascript

Invariants: a trap cannot lie about everything

The engine checks traps against the target. If the target has a non-configurable, non-writable property id with value 1, a get trap that answers 2 throws a TypeError, and ownKeys must still list every non-configurable key. Hiding ordinary configurable keys is allowed:

javascript

Limits worth knowing

  • A proxy is a different object: new Proxy(o, {}) !== o, so identity checks and WeakMap keys see two objects.
  • Built-ins with internal slots (Map, Set, Date) reject a proxy as receiver: new Proxy(new Map(), {}).set('a', 1) throws TypeError. Return methods bound to the target from get.
  • Proxy.revocable(target, handler) gives { proxy, revoke }; after revoke() every operation on the proxy throws TypeError.
  • Every access pays for a function call. Use proxies at boundaries (validation, reactivity), not in hot inner loops.

Common mistakes

  • Reading proxy[key] inside a trap on the same proxy. It re-enters the trap forever; use target or Reflect.
  • Forgetting to return a value from get, so every property reads as undefined.
  • Trapping get and calling key.startsWith(...) when the engine passes a symbol such as Symbol.toPrimitive.

Your exercise

You will build a guarded settings store from five traps. The usual slip is set: it must return false for a refusal and true for a success, and the starter runs in strict mode, so a wrong answer is visible as a TypeError.

Up nextWeakRef, WeakMap, WeakSetProxy and Memory

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…