JavaScript Proxy
A Proxy is a JavaScript object that can wrap other objects.
What is a Proxy?
A Proxy is a JavaScript object that can wrap other objects.
A Proxy lets you control operations on other objects.
A Proxy can trap and intercept code when someone is:
- Reading a property (get)
- Setting a property (set)
- Deleting a property (deleteProperty)
- Checking if a property exists (has)
- Calling a function (apply)
- Constructing an object (construct)
Example
Example Code
javascriptconst proxy = new Proxy(target, handler);- target - the original object or function
- handler - an object with trap methods
Example
Example Code
javascriptconst myObject = {name: "Jan"};
const proxy = new Proxy(myObject, {
get(target, prop) {
return target[prop];
}
});Proxy Logging
A typical Proxy example is logging of object changes.
Below is a demo that:
- Wraps an object in a Proxy
- Logs whenever a property is read or written
- Logs each get and set operation in real time
Example
Example Code
javascript// Create an Object
const user = { name: "Jan", age: 40 };
//Create a Proxy
const proxy = new Proxy(user, {
get(target, property) {
log("Getting: " + property);
return target[property];
},
set(target, property, value) {
log("Setting: " + property);
return target[property];
}
});
proxy.name = "John";
proxy.age = 42;
let text1 = proxy.name;
let text2 = proxy.ageProxy with Reflect (Most Common)
Below is a demo that:
- Wraps an object in a Proxy
- Logs whenever a property is read or written
- Uses Reflect.get() and Reflect.set() inside the Proxy handlers
- get trap uses Reflect.get(target, property, receiver)
- set trap uses Reflect.set(target, property, value, receiver)
- Reflect makes the Proxy behavior match the normal object behavior
Example
Example Code
javascript// Create an Object
const user = { name: "Jan", age: 40 };
// Create a Proxy
const proxy = new Proxy(user, {
get(target, property) {
log("Getting: " + property);
// safe forwarding
return Reflect.get(target, property);
},
set(target, property, value) {
log("Setting: " + property);
// safe forwarding
return Reflect.set(target, property, value);
}
});
proxy.name = "John";
proxy.age = 42;
let text1 = proxy.name;
let text2 = proxy.ageProxy with Reflect Flow
The flow below is the essence of JavaScript metaprogramming with Proxy + Reflect.
Flow Explanation:
- Your code interacts with an object
- Proxy intercepts the operation
- Your trap code decides what to do
- Reflect forwards the operation safely
- The target object receives the real action
Why Proxies?
Proxies allow you to:
- Add logging
- Validate changes
- Auto-generate properties
- Protect sensitive data
- Create virtual or computed objects
- Intercept function calls
- Create reactive systems (like Vue.js)
Proxy Validation
Example
Example Code
javascript// Create an Object
const user = { name: "Jan", age: 40 };
// Create a Proxy
const proxy = new Proxy(user, {
set(target, prop, value) {
if (prop === "age" && value **Metaprogramming**
> Metaprogramming lets JavaScript:
> Intercept behavior
> Modify behavior
> Define new behavior
> Generate behavior dynamically
> It gives developers deep control over the language's inner workings.
---
## Proxy Traps
A trap is a function inside a Proxy handler.
It runs whenever a specific operation is performed on the Proxy.
Below is a complete and accurate explanation of every JavaScript Proxy trap, what triggers them, their parameters, and what they are expected to return.
| Trap Name | Triggered when |
| --- | --- |
| get | A property is read |
| set | A property is changed |
| has | Using the in operator |
| deleteProperty | A property is deleted |
| apply | A function is called |
| construct | An object is cretated (with new) |
| getOwnPropertyDescriptor | A property descriptor is retrieved |
| defineProperty | A property is defined |
| getPrototypeOf | A prototype is retrieved |
| setPrototypeOf | A prototype is set |
| isExtensible | Extensibility is checked |
| preventExtensions | Existenibility is prevented |
| ownKeys | Properties are listed |
> The list above is 2025-accurate and includes all 13 Proxy traps defined in ECMAScript.
> Each trap handler is decribed below.
---
## handler.get()
Triggered when a **property is read**:
### Examplejavascript get(obj, prop, receiver) {
return Reflect.get(obj, prop, receiver);
}
Example Code
html**Parameters**
- obj - the target object
- prop - the property being accessed
- receiver - the this value for getters (usually the proxy itself)
**Must Return**
- The property value
---
## handler.set()
Triggered when a **property is assigned a value**:
### Examplejavascript set(obj, prop, value, receiver) {
return Reflect.set(obj, prop, value, receiver);
}
Example Code
html#### Parameters
- obj - the target object
- prop - the property being set
- value - the new property value
- receiver - the object that received the assignment (usually the proxy)
#### Must Return
- true - if the assignment succeeded
- false - if the assignment failed
Throwing an error is also allowed.
---
## handler.has()
Intercepts the **in** operator.
### Examplejavascript has(obj, prop) {
return Reflect.has(obj, prop);
}
Example Code
html**Parameters**
- obj - the target object
- prop - the property being accessed
- receiver - the value of this for setters (usually the proxy itself)
**Must Return**
- true
- false
---
## handler.deleteProperty()
Intercepts the **delete** operator.
### Examplejavascript deleteProperty(obj, prop) {
return Reflect.deleteProperty(obj, prop);
}
Example Code
html**Parameters**
- obj - the target object
- prop - the property to delete
**Must Return**
- true - for sucess
- false - for failure
---
## handler.apply()
Triggered when a **function is called**:
### Examplejavascript apply(func, thisArg, args) {
return Reflect.apply(func, this, args);
}
Example Code
html**Parameters**
- func - the callable object (function)
- this - the this argument for the call
- args - the function arguments array
**Must Return**
- The return value of the function
---
## handler.construct
Intercepts the **new** operator.
### Examplejavascript construct(obj, args, newTarget) {
return Reflect.construct(obj, args, newTarget);
}
Example Code
html**Parameters**
- obj - the constructor object
- args - the array of arguments passed
- newTarget - the constructor
**Must Return**
- An Object (The new instance)
### Examplejavascript const obj = {} // No trap
Object.create() // No trap
class User {};
new User(); // No trap
Example Code
html---
## handler.getOwnPropertyDescriptor()
Intercepts property descriptor retrieval.
### Examplejavascript getOwnPropertyDescriptor(obj, prop) {
return Reflect.getOwnPropertyDescriptor(obj, prop);
}
Example Code
html**Parameters**
- obj - the target object
- prop - the property to describe
**Must Return**
- A property descriptor
- undefined
---
## handler.defineProperty()
Intercepts Object.defineProperty().
### Examplejavascript defineProperty(obj, prop, descriptor) {
return Reflect.defineProperty(obj, prop, descriptor);
}
Example Code
html**Parameters**
- obj - the target object
- prop - the property to describe
- descriptor - the property descriptor
**Must Return**
- true - if sucess
- false - if not
---
## handler.getPrototypeOf()
Intercepts prototype lookup.
### Examplejavascript getPrototypeOf(obj) {
return Reflect.getPrototypeOf(obj);
}
Example Code
html**Parameters**
- obj - the target object
**Must Return**
- An Object
- null
---
## handler.setPrototypeOf()
Intercepts setting the prototype.
### Examplejavascript setPrototypeOf(obj, prototype) {
return Reflect.setPrototypeOf(obj, prototype);
}
Example Code
html**Parameters**
- obj - the target object
- prototype - the new prototype or null
**Must Return**
- An Object
- null
---
## handler.isExtensible()
Intercepts checking if an object is extensible.
### Examplejavascript isExtensible(obj) {
return Reflect.isExtensible(obj);
}
Example Code
html**Parameters**
- obj - the target object
**Must Return**
- true - for yes
- false - for no
---
## handler.preventExtentions()
Intercepts making an object non-extensible.
### Examplejavascript preventExtensions(obj) {
return Reflect.preventExtensions(obj);
}
Example Code
html**Parameters**
- obj - the target object
**Must Return**
- true - for success
- false - for failure
---
## handler.ownKeys()
Intercepts operations listing keys (property names or symbols).
### Examplejavascript ownKeys(obj) {
return Reflect.ownKeys(obj);
}
Example Code
html**Parameters**
- obj - the target object
**Must Return**
- array of keys with no duplicates
---
## Proxy Traps Map Reflect Methods
A Proxy trap represents one of JavaScript's internal operations:
- [[Construct]]
- [[Call]]
- [[Get]]
- [[Set]]
- [[HasProperty]]
- [[Delete]]
- [[DefineProperty]]
- [[GetOwnProperty]]
- [[OwnPropertyKeys]]
- [[GetPrototypeOf]]
- [[SetPrototypeOf]]
- [[PreventExtensions]]
- [[IsExtensible]]
These internal operations are what JavaScript uses (inside the engine) when you access or modify objects.
When a Proxy intercepts one of these operations, they should be forwarded correctly:
### Examplejavascript get(target, property, receiver) {
return Reflect.get(target, property, receiver);
} ```
Reflect is used because Reflect methods are 1-to-1 mirrors of the internal operations.
- They produce correct return values (true/false/descriptor)
- They avoid throwing errors that would break Proxy rules
- They make the Proxy behave like normal JavaScript objects (unless modified)
JavaScript Internals Became Reflect
Before ES6 (2015), many fundamental operations did not exist as functions: | Operation | Before E6 | Problem | | --- | --- | --- | | get property | obj[prop] | Not callable as a function | | set property | obj[prop] = value | Not callable as a function | | delete property | delete obj[prop] | Operator, not a function | | check property | "prop" in obj | Operator, not a function | | construct (new) | new Foo() | Not callable generically | | get prototypes | Object.getPrototypeOf(obj) | Throws on non-objects | | define property | Object.defineProperty() | Returns object instead of boolean | | own keys | Object.keys() | Not complete (misses symbols) | These were incomplete and inconsistent for Proxy forwarding.
So ES6 (2015) added Reflect:
| Internal Operation | Reflect Method |
|---|---|
| [[Construct]] | Reflect.construct() |
| [[Call]] | Reflect.apply() |
| [[Get]] | Reflect.get() |
| [[Set]] | Reflect.set() |
| [[HasProperty]] | Reflect.has() |
| [[Delete]] | Reflect.deleteProperty() |
| [[DefineProperty]] | Reflect.defineProperty() |
| [[GetOwnProperty]] | Reflect.getOwnProperty() |
| [[OwnPropertyKeys]] | Reflect.ownPropertyKeys() |
| [[IsExstensible]] | Reflect.isExtensible() |
| [[PreventExstensions]] | Reflect.preventExtensions() |
| [[GetPrototypeOf]] | Reflect.getPrototypeOf() |
| [[SetPrototypeOf]] | Reflect.setPrototypeOf() |
Interactive Code Examples
Example 1
javascriptconst proxy = new Proxy(target, handler);JS Example 2
javascriptconst myObject = {name: "Jan"};
const proxy = new Proxy(myObject, {
get(target, prop) {
return target[prop];
}
});JS Example 3
javascript// Create an Object
const user = { name: "Jan", age: 40 };
//Create a Proxy
const proxy = new Proxy(user, {
get(target, property) {
log("Getting: " + property);
return target[property];
},
set(target, property, value) {
log("Setting: " + property);
return target[property];
}
});
proxy.name = "John";
proxy.age = 42;
let text1 = proxy.name;
let text2 = proxy.ageJS Example 4
javascript// Create an Object
const user = { name: "Jan", age: 40 };
// Create a Proxy
const proxy = new Proxy(user, {
get(target, property) {
log("Getting: " + property);
// safe forwarding
return Reflect.get(target, property);
},
set(target, property, value) {
log("Setting: " + property);
// safe forwarding
return Reflect.set(target, property, value);
}
});
proxy.name = "John";
proxy.age = 42;
let text1 = proxy.name;
let text2 = proxy.ageJS Example 5
javascriptJS Example 6
javascript// Create an Object
const person = {
first: "John",
last: "Doe"
};
// Create a Proxy
const virtual = new Proxy(person, {
get(target, prop) {
if (prop === "fullName") {
return target.first + " " + target.last;
}
return Reflect.get(target, prop);
}
});
let text = virtual.fullName; // "John Doe"