Proxies, Reflect & Symbols
18 min read
ProxyReflectSymbolsMeta-ProgrammingTrapsSymbol.iteratorWell-Known Symbols
Meta-Programming in JavaScript
Proxy: Intercepting Object Operations
A Proxy wraps an object and intercepts fundamental operations like property access, assignment, function calls, etc.
const validator = new Proxy({}, {
set(target, prop, value) {
if (prop === "age") {
if (!Number.isInteger(value) || value < 0 || value > 150) {
throw new RangeError("Age must be 0-150");
}
}
target[prop] = value;
return true;
},
get(target, prop) {
return prop in target ? target[prop] : `No property: ${prop}`;
},
deleteProperty(target, prop) {
if (prop === "id") throw new Error("Cannot delete id");
delete target[prop];
return true;
}
});Proxy Traps Reference
| Trap | Intercepts |
|---|---|
get | Property reading |
set | Property writing |
has | in operator |
deleteProperty | delete operator |
apply | Function calls |
construct | new operator |
ownKeys | Object.keys(), for...in |
Reflect API
Reflect provides default behavior for all Proxy traps. Always use Reflect inside traps for safety.
const logged = new Proxy(target, {
get(target, prop, receiver) {
console.log(`GET ${String(prop)}`);
return Reflect.get(target, prop, receiver); // Correct default behavior
},
set(target, prop, value, receiver) {
console.log(`SET ${String(prop)} = ${value}`);
return Reflect.set(target, prop, value, receiver);
}
});Symbols
Symbols create unique, immutable identifiers — perfect for object properties that should never collide.
const id = Symbol("id");
const user = { [id]: 123, name: "Alice" };
user[id]; // 123
Object.keys(user); // ["name"] — symbols are hidden!
JSON.stringify(user); // {"name":"Alice"} — symbols excluded
// Well-Known Symbols
class Range {
constructor(start, end) { this.start = start; this.end = end; }
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
return {
next() {
return current <= end
? { value: current++, done: false }
: { done: true };
}
};
}
}
for (const n of new Range(1, 5)) console.log(n); // 1, 2, 3, 4, 5
[...new Range(1, 3)]; // [1, 2, 3]