Reflect
This lesson explains Reflect with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.
ES6+ Reflect Overview
Reflect is a built-in object introduced in ES6 that
provides methods for performing interceptable JavaScript operations.
Each method corresponds to an internal object operation and mirrors
the traps available on a Proxy handler.
Reflect methods return predictable results instead of throwing errors
in many cases. This makes them especially useful inside proxy
handlers, metaprogramming utilities, and libraries that need to
work with objects dynamically.
| Feature | Description |
| Introduced In | ES6 (ECMAScript 2015) |
| Type | Built-in static object |
| Purpose | Perform object operations in a standard way |
| Proxy Relation | Method names match Proxy trap names |
| Return Style | Often returns booleans instead of throwing |
| Common Uses | Proxy handlers, dynamic property access, forwarding |
Basic Reflect Example
const user = {
name: "Alex",
role: "admin"
};
console.log(
Reflect.get(user, "name")
);
Reflect.set(user, "role", "editor");
console.log(
Reflect.has(user, "email")
);
console.log(user);
Reflect.get() reads a property,
Reflect.set() updates one, and
Reflect.has() checks whether a property exists on the
target object.
How Reflect Works
Reflect exposes standard object operations as named methods. Instead
of mixing direct property access with older APIs such as
Object.defineProperty(), you can use one consistent
interface.
| Step | Description | Example |
| Choose Operation | Pick the Reflect method for the task. | Reflect.get() |
| Pass Target | Provide the object being operated on. | user |
| Pass Key or Args | Supply property name and value if needed. | "name" |
| Receive Result | Get value, boolean, or descriptor back. | true |
| Use in Proxy | Forward to default behavior in handlers. | Reflect.set(...args) |
Reflect Methods Reference
| Method | Purpose | Returns |
Reflect.get() | Read a property value. | Property value |
Reflect.set() | Assign a property value. | Boolean success |
Reflect.has() | Check if property exists. | Boolean |
Reflect.deleteProperty() | Delete a property. | Boolean success |
Reflect.defineProperty() | Define or update a property descriptor. | Boolean success |
Reflect.getOwnPropertyDescriptor() | Get descriptor for one property. | Descriptor or undefined |
Reflect.ownKeys() | Get all own property keys. | Array of keys |
Reflect.apply() | Call a function with arguments. | Function return value |
Reflect.construct() | Create an instance with new. | New object instance |
Reflect.get and Reflect.set
const product = {
title: "Keyboard",
price: 79
};
const title =
Reflect.get(product, "title");
const updated =
Reflect.set(
product,
"price",
69
);
console.log(title);
console.log(updated);
console.log(product.price);
These methods behave like normal property access and assignment, but
they work well when the property name is stored in a variable or
when you need a function-style API.
Reflect.has and Reflect.deleteProperty
const settings = {
theme: "dark",
debug: true,
beta: false
};
console.log(
Reflect.has(settings, "debug")
);
const removed =
Reflect.deleteProperty(
settings,
"beta"
);
console.log(removed);
console.log(settings);
Reflect.has() is similar to the
in operator, while
Reflect.deleteProperty() is similar to
delete, but both return clear boolean results.
Reflect.defineProperty
const account = {
balance: 1000
};
const defined =
Reflect.defineProperty(
account,
"balance",
{
value: 1000,
writable: false,
enumerable: true,
configurable: false
}
);
console.log(defined);
console.log(account.balance);
account.balance = 2000;
console.log(account.balance);
Use Reflect.defineProperty() when you need precise
control over property attributes such as writability and
enumerability.
Reflect.ownKeys
const id = Symbol("id");
const record = {
name: "Sam",
active: true,
[id]: 42
};
const keys =
Reflect.ownKeys(record);
console.log(keys);
Reflect.ownKeys() returns both string keys and symbol
keys, making it useful for introspection and serialization tools.
Reflect.apply and Reflect.construct
function greet(name, role) {
return `Hello ${name}, you are a ${role}`;
}
class User {
constructor(name) {
this.name = name;
}
}
const message =
Reflect.apply(
greet,
null,
["Alex", "developer"]
);
const user =
Reflect.construct(
User,
["Riya"]
);
console.log(message);
console.log(user);
Reflect.apply() calls a function with a specific
this value and argument list.
Reflect.construct() creates an object as if
new were used.
Reflect with Proxy Handlers
const target = {
count: 0
};
const handler = {
get(obj, key, receiver) {
console.log(`Reading ${String(key)}`);
return Reflect.get(
obj,
key,
receiver
);
},
set(obj, key, value, receiver) {
console.log(
`Setting ${String(key)} to ${value}`
);
return Reflect.set(
obj,
key,
value,
receiver
);
}
};
const proxy =
new Proxy(target, handler);
proxy.count = 5;
console.log(proxy.count);
The most common real-world use of Reflect is inside Proxy handlers.
Forwarding to Reflect keeps default object behavior intact while
adding custom logging, validation, or access control.
Validation Proxy with Reflect
function createValidatedUser(data) {
return new Proxy(data, {
set(target, key, value) {
if (
key === "age" &&
typeof value !== "number"
) {
throw new TypeError(
"Age must be a number"
);
}
return Reflect.set(
target,
key,
value
);
}
});
}
const user =
createValidatedUser({
name: "Alex",
age: 28
});
user.age = 30;
console.log(user.age);
Reflect makes it easy to add validation or transformation logic in
a proxy and still return the correct boolean result from
set traps.
Reflect vs Object Methods
| Operation | Reflect | Object / Operator |
| Read property | Reflect.get(obj, "key") | obj.key |
| Set property | Reflect.set(obj, "key", value) | obj.key = value |
| Check property | Reflect.has(obj, "key") | "key" in obj |
| Delete property | Reflect.deleteProperty(obj, "key") | delete obj.key |
| Define property | Returns boolean | Object.defineProperty() may throw |
Common Reflect Use Cases
- Forwarding operations inside Proxy handlers.
- Dynamic property access when keys come from variables.
- Building object utilities and schema validators.
- Framework code that inspects or modifies objects safely.
- Calling functions or constructors programmatically.
- Collecting own keys including symbol properties.
Reflect Best Practices
- Use Reflect inside Proxy traps to preserve default behavior.
- Prefer Reflect when you need boolean success results.
- Keep proxy handlers small and forward unhandled cases to Reflect.
- Use descriptive logging before forwarding in debug utilities.
- Validate input before calling Reflect on unknown objects.
- Learn Reflect together with Proxy for metaprogramming tasks.
- Avoid Reflect for simple static property access when direct syntax is clearer.
Common Reflect Mistakes
- Forgetting to return the result of
Reflect.set() in proxy traps. - Using Reflect everywhere instead of normal property syntax.
- Assuming Reflect methods always succeed without checking booleans.
- Not passing the
receiver argument when needed in getters. - Confusing
Reflect.has() with Object.hasOwn(). - Trying to use Reflect without understanding Proxy behavior first.
- Mutating frozen or sealed objects and ignoring failed boolean results.
Reflect vs Proxy
| Feature | Reflect | Proxy |
| Role | Performs default object operations. | Intercepts object operations. |
| Usage | Direct method calls. | Wrap target with handler traps. |
| Best For | Forwarding and standard behavior. | Custom behavior and control. |
| Together | Often used inside Proxy handlers. | Provides interception layer. |
Key Takeaways
- Reflect provides a standard API for object operations in ES6+.
- Its methods mirror Proxy trap names such as
get, set, and has. - Reflect is especially useful for forwarding behavior in proxy handlers.
- Many Reflect methods return booleans instead of throwing errors.
- Use Reflect intentionally for dynamic or metaprogramming tasks.
Pro Tip
In a Proxy set trap, always
return Reflect.set(...). Returning
false or forgetting the return value can silently break
assignment behavior.