JavaScript Proxy get Trap: Intercept Property Reads
JavaScript Proxies provide a powerful mechanism to intercept and
customize fundamental language operations on objects. This article
explains how the Proxy handler’s get trap functions to
intercept property reading operations, detailing its parameters, return
behaviors, and invariants, along with practical code examples
demonstrating its use for fallback values and dynamic properties.
What is the get Trap?
In JavaScript, a Proxy wraps a target object and enables
the interception of internal operations via a handler object. The
get trap intercepts any attempt to read a property from the
proxy instance.
Operations that trigger the get trap include: - Dot
notation: proxy.property - Bracket notation:
proxy['property'] - Object inheritance lookups:
Object.create(proxy).property - Methods like
Reflect.get(proxy, property)
When any of these operations occur, the JavaScript engine suspends
default property resolution and instead executes the get
method defined on the proxy’s handler.
Syntax and Parameters
The get trap is defined as a method within the handler
object passed to the Proxy constructor:
const handler = {
get(target, prop, receiver) {
// Custom logic here
}
};
const proxy = new Proxy(targetObject, handler);The method accepts three parameters:
target: The original target object wrapped by the proxy.prop: The name (astringorSymbol) of the property being accessed.receiver: Thethisvalue used for the property access, which is usually the proxy instance itself or an object that inherits from it.
How Interception Works
When a read operation is attempted, the get trap
function executes and determines the final return value.
Basic Interception and Default Fallbacks
const user = {
name: "Alice",
age: 30
};
const handler = {
get(target, prop, receiver) {
if (prop in target) {
return target[prop];
}
return `Property '${String(prop)}' does not exist.`;
}
};
const proxyUser = new Proxy(user, handler);
console.log(proxyUser.name); // "Alice"
console.log(proxyUser.email); // "Property 'email' does not exist."In this example, accessing proxyUser.name returns the
value from the target, while accessing an undefined
property like proxyUser.email returns a custom fallback
message instead of undefined.
Using Reflect.get()
The recommended practice when forwarding operations to the underlying
target is using Reflect.get(). This ensures
that getters with this references execute within the
correct context (the receiver):
const handler = {
get(target, prop, receiver) {
console.log(`Accessing property: ${String(prop)}`);
return Reflect.get(target, prop, receiver);
}
};
const proxy = new Proxy({ a: 1 }, handler);
console.log(proxy.a);
// Logs: "Accessing property: a"
// Returns: 1Trap Invariants
JavaScript enforces specific rules (invariants) to guarantee predictable behavior even when traps are used:
- If the target property is a non-writable, non-configurable data property, the trap must return the exact same value as the target’s property.
- If the target property is a non-configurable
accessor with an
undefinedgetter, the trap must returnundefined.
Violating these invariants will cause the JavaScript runtime to throw
a TypeError.