cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Reflect

Learn the Reflect API: a function-based service desk for object operations, proxy forwarding, own keys, receivers, apply, and construct.

By the end, you can
  • 01
    Name the service-desk methodsMatch common object operations to the Reflect method that performs them.
  • 02
    Forward proxy traps safelyUse matching Reflect calls and return the booleans strict mode expects.
  • 03
    Preserve receiversExplain why Reflect.get(target, key, receiver) matters for getters.

Reflect is the object model’s service desk

JavaScript already has many ways to perform object operations: dot access, bracket access, in, delete, new, Object.defineProperty, and Function.prototype.apply. Reflect gathers the core operations behind those tools into plain functions.

That sounds abstract until you write a Proxy. A proxy trap intercepts an operation, and very often you want to log, validate, or tweak one thing, then do the normal operation. Reflect gives you the matching official forwarding function.

Real-life analogyReflect is the official service desk

Imagine a building where many small tasks normally happen by gestures: opening a door, checking a name plate, removing a sign. Reflect is the desk where you can request those same tasks by filling out a clear form. The answer is often a simple yes or no.

In real life: Ask the desk to check whether a room exists
In JavaScript: Reflect.has(target, key)
In real life: Ask the desk to unlock or delete a room
In JavaScript: Reflect.deleteProperty(target, key)
In real life: Ask the desk to create a room and report success
In JavaScript: Reflect.defineProperty(target, key, descriptor)
In real life: The desk says yes or no instead of shouting
In JavaScript: Many mutating Reflect methods return booleans

Where the analogy stops: The service desk does not make impossible operations possible. It still follows descriptors, extensibility, proxy invariants, and TypeError rules for non-object targets.

The short version

Reflect is a namespace of 13 methods that match the 13 proxy traps. Use it when you want the function form of an operation, especially inside proxy traps.

In this lesson you will compare Reflect with Object methods, preserve a getter’s receiver, forward proxy traps, inspect key order, and use Reflect.apply and Reflect.construct for advanced calls.

The 13 Reflect methods map to operations

SORTER

Reflect is not magic. Each method is a named function for an operation JavaScript already knows how to do. The full list is: apply, construct, defineProperty, deleteProperty, get, getOwnPropertyDescriptor, getPrototypeOf, has, isExtensible, ownKeys, preventExtensions, set, and setPrototypeOf.

Common Reflect methods
OperationReflect methodImportant return
Read a propertyReflect.get(target, key, receiver?)The property value; accepts a receiver for getters.
Write a propertyReflect.set(target, key, value, receiver?)true when the write succeeds, false when it is blocked.
Check a keyReflect.has(target, key)Boolean, like the in operator.
Delete a keyReflect.deleteProperty(target, key)Boolean, like delete target[key] but callable.
List every own keyReflect.ownKeys(target)String keys and symbol keys, including non-enumerable ones.
Call or constructReflect.apply / Reflect.constructThe return value of the call or the newly constructed object.

The methods that change shape or write state often return a boolean: defineProperty, set, deleteProperty, preventExtensions, and setPrototypeOf. That boolean is especially useful in strict-mode code and proxy traps.

Boolean-returning methods
Reflect methodWhen it returns false
Reflect.definePropertyThe descriptor cannot be installed, for example on a non-extensible object.
Reflect.setThe write is blocked by a setter, descriptor, or proxy invariant.
Reflect.deletePropertyA non-configurable property cannot be deleted.
Reflect.preventExtensionsThe object cannot be made non-extensible.
Reflect.setPrototypeOfThe prototype change is not allowed.
Sort the operation
  • Get user.name while preserving a getter receiver
  • Assign user.name = value from a trap
  • Check whether name in user is true
  • List strings, symbols, and hidden own keys
  • Install a descriptor and get true or false
  • Try to change an object's prototype
  • Call a function with a chosen this and an args array
  • Call a constructor with a custom new.target
Try it yourself
0 of 8 correct

Drag each card to the kind of operation its Reflect method performs.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Reflect vs Object and syntax

STEP THROUGH

Some Object methods and operators throw or coerce in ways that are awkward when you are writing generic code. Object.defineProperty throws if it cannot define; Reflect.defineProperty returns false. Object.getPrototypeOf(1) coerces a primitive wrapper in modern JavaScript, while Reflect.getPrototypeOf(1) throws TypeError because Reflect expects an object target.

Object throws; Reflect reports
Step 0 of 5Ready
Your turn: follow the blue line

Step through the same failing definition with Object and Reflect. Predict which one throws and which one returns a boolean.

Running in
  1. script
Next: line 2
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
"use strict";let objectResult;try {  Object.defineProperty(locked, "id", { value: 1 });} catch (error) {  objectResult = error.name;}const reflectResult = Reflect.defineProperty(locked, "id", { value: 1 });console.log(objectResult);console.log(reflectResult);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Here is the broader quick map: Reflect.has mirrors in, Reflect.deleteProperty mirrors delete, and Reflect.ownKeys sees more keys than Object.keys.

Reflect versus syntax quick lab
Object operation mapPop out in the code editor (opens in a new tab)JavaScript
const box = { visible: 1 };const sym = Symbol("tag");Object.defineProperty(box, "hidden", { value: 2 });box[sym] = 3; console.log(Reflect.has(box, "visible"));console.log(Reflect.deleteProperty(box, "missing"));console.log(Reflect.ownKeys(box));console.log(Object.keys(box));
Compareservice desk

Run this in a console to see booleans for has/delete, then compare the all-keys list with the enumerable string-only list.

Try it yourself
Compare the paired operations.

Reflect.has matches in, Reflect.deleteProperty matches delete, and Reflect.ownKeys sees more than Object.keys. Reflect methods still throw TypeError when the target must be an object and you pass a primitive.

A compact map of common operations before the deeper receiver and proxy labs.
Operation pairsPop out in the code editor (opens in a new tab)JavaScript
const box = { visible: 1 };
const sym = Symbol("tag");
Object.defineProperty(box, "hidden", { value: 2 });
box[sym] = 3;

console.log(Reflect.has(box, "visible"));
console.log(Reflect.deleteProperty(box, "missing"));
console.log(Reflect.ownKeys(box));
console.log(Object.keys(box));

Receivers: who is asking?

INTERACTIVE

The receiver is the object that should become this when a getter or setter runs. With plain obj.value, the receiver is usually obj. In inheritance and proxies, the target that owns the getter and the object that asked for the value can be different.

Real-life analogyThe receiver is who is asking

If a getter says “look at my name badge,” JavaScript must know whose badge it means. The receiver is that person at the counter. Reflect lets you pass the badge along instead of accidentally swapping it.

In real life: A receptionist answers a question for the person at the counter
In JavaScript: A getter runs with this set to the receiver
In real life: Forwarding the request but changing the person’s name badge
In JavaScript: Using target[key] can run the getter with the wrong this
In real life: Forwarding the exact request slip
In JavaScript: Reflect.get(target, key, receiver) preserves the asker

Where the analogy stops: The receiver matters only for operations that use this, such as getters, setters, and some proxy chains. A plain data property just returns its stored value.

Forward a getter with or without the receiver
Step 0 of 6Ready
Your turn: follow the blue line

Switch line 12. The printed value is the same here, but the explanation shows why receiver matters for getters and proxies.

Running in
  1. script
Next: line 2
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
"use strict";  name: "prototype badge",  get label() {    return this.name;  }};const user = Object.create(badge);user.name = "Ada";const proxy = new Proxy(user, {  get(target, key, receiver) {    return target[key];  }});console.log(proxy.label);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose line 12 before stepping

Both print the same simple value here. The Reflect version preserves who asked when getters keep reading.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

In a simple example both versions may print the same value. The bug appears when the getter does more work, when a setter validates using this, or when another proxy should see the nested name read. Inside a proxy get trap, prefer return Reflect.get(target, key, receiver).

Forwarding traps with the matching Reflect method

STEP THROUGH

A proxy handler often looks like a switchboard: log the operation, then forward it. The safest default is to accept the trap’s arguments with ...args and pass those exact arguments to the matching Reflect method.

A logging proxy forwards with Reflect
Step 0 of 7Ready
Your turn: follow the blue line

Follow a logging proxy that forwards with Reflect. Watch for the boolean returned by Reflect.set.

Running in
  1. script
Next: line 2
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
"use strict";const log = [];const proxy = new Proxy(target, {  get(...args) {    log.push("get:" + String(args[1]));    return Reflect.get(...args);  },  set(...args) {    log.push("set:" + String(args[1]));    return Reflect.set(...args);  }});proxy.count = proxy.count + 1;console.log(target.count);console.log(log.join(", "));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Return the boolean from set

A set trap must return a boolean. In strict mode, if it returns false or accidentally returns undefined, the assignment throws a TypeError. return Reflect.set(...args) both performs the normal write and returns the success flag.

Reflect.ownKeys sees the whole key shelf

INTERACTIVE

Object.keys is intentionally friendly: own, enumerable, string keys only. Reflect.ownKeys is the complete own-key list: integer-like string keys in ascending order, then other string keys in insertion order, then symbols in insertion order. It includes non-enumerable keys.

ownKeys order lab
Keys under testPop out in the code editor (opens in a new tab)JavaScript
const sym = Symbol("id");const record = { 20: "twenty", name: "Ada", 3: "three" };Object.defineProperty(record, "hidden", { value: true });record[sym] = "symbol value"; console.log(Reflect.ownKeys(record));console.log(Object.keys(record));
Real orderstrings and symbols
  • Reflect.ownKeys3, 20, name, hidden, Symbol(id)
  • Object.keys3, 20, name
Try it yourself

The underlying run always uses Reflect.ownKeys. The toggles only help you compare which parts Object.keys would leave out. Integer-like keys appear first in numeric order.

Compare all own keys with enumerable string keys. Reset restores the complete Reflect list.

That ordering is why arrays and array-like objects feel consistent, while symbols still remain separate from ordinary string names. Review the Symbols lesson if symbol keys are still new.

Reflect.apply and Reflect.construct

INTERACTIVE

Reflect.apply(fn, thisArg, args) calls a function with a chosen this and an array-like list of arguments. It is the modern, symmetrical cousin of fn.apply(thisArg, args), which you met in the call, apply & bind lesson.

Reflect.construct(Target, args, NewTarget) is more unusual. It runs Target as a constructor, but the optional third argument controls new.target inside the constructor and the prototype used for the created object. That connects to the lessons on constructors and new.

apply and construct lab
Call and constructPop out in the code editor (opens in a new tab)JavaScript
function total(prefix, ...numbers) {  return prefix + numbers.reduce((sum, n) => sum + n, 0);}function Base(name) {  this.name = name;  this.createdBy = new.target === Special ? "Special" : "Base";}function Special() {} console.log(Reflect.apply(total, null, ["$", 2, 3, 4]));const item = Reflect.construct(Base, ["Ada"], Special);console.log(item.createdBy);console.log(Object.getPrototypeOf(item) === Special.prototype);
Real resultReflect
  • Reflect.apply$9
  • new.target labelSpecial
  • Special prototype?true
Try it yourself
Read the three results from the real run.

Reflect.apply calls a function with an argument array. Reflect.construct calls Base, but the third argument makes new.target and the final prototype come from Special.

The lesson uses explicit text labels instead of reading function names at runtime, because production minifiers may rename site functions.
Apply and construct sourcePop out in the code editor (opens in a new tab)JavaScript
function total(prefix, ...numbers) {
  return prefix + numbers.reduce((sum, n) => sum + n, 0);
}
function Base(name) {
  this.name = name;
  this.createdBy = new.target === Special ? "Special" : "Base";
}
function Special() {}

console.log(Reflect.apply(total, null, ["$", 2, 3, 4]));
const item = Reflect.construct(Base, ["Ada"], Special);
console.log(item.createdBy);
console.log(Object.getPrototypeOf(item) === Special.prototype);

Where you’ll use Reflect

Reflect shows up most often in libraries: validation proxies, observable objects, RPC layers, test doubles, data mappers, and frameworks that need to forward JavaScript’s normal object behavior while adding a little work around it.

Validation proxy

Check a value in set, then return Reflect.set(...args) if it is valid.

Debug logger

Log get, set, and deleteProperty without reimplementing descriptors.

Descriptor installer

Try a definition and branch on Reflect.defineProperty returning false.

Serialization tool

Use Reflect.ownKeys when non-enumerable or symbol metadata matters.

The habit is simple: if you are inside a proxy trap and want ordinary behavior, reach for the matching Reflect method first. Then add only the extra behavior you actually need.

Common misconceptions

  • “Reflect never throws.” Many methods return booleans for operation failure, but Reflect methods still throw TypeError when the target must be an object and is not.
  • “Reflect is only for proxies.” Proxies are the main use, but the function forms are useful in generic helpers too.
  • “Reflect.ownKeys is the same as Object.keys.” It includes non-enumerable strings and symbols; Object.keys does not.
  • “The receiver is always the target.” In inherited getters and proxy traps, the receiver can be the original object that asked.
  • “Reflect.construct just avoids new.” Its third argument controls new.target and the new object’s prototype.
  • “A set trap can forget to return.” In strict mode that becomes undefined, which means failure and throws.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict Object vs Reflect

Read the code and predict the two console lines.

Starter codePop out in the code editor (opens in a new tab)JavaScript
"use strict";
const box = Object.preventExtensions({});
let objectResult;
try { Object.defineProperty(box, "x", { value: 1 }); } catch (error) { objectResult = error.name; }
console.log(objectResult);
console.log(Reflect.defineProperty(box, "x", { value: 1 }));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeUse a receiver

    Explain why this prints the user’s name even though the getter is stored on the prototype.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    "use strict";
    const proto = { get label() { return this.name; } };
    const user = Object.create(proto);
    user.name = "Ada";
    console.log(Reflect.get(proto, "label", user));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeList every own key

      Predict the joined key order.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const sym = Symbol("s");
      const obj = { 2: "two", first: 1, 1: "one" };
      Object.defineProperty(obj, "hidden", { value: true });
      obj[sym] = 9;
      console.log(Reflect.ownKeys(obj).map((key) => typeof key === "symbol" ? key.toString() : key).join("|"));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeFind the set-trap bug

        What error name prints, and what one-word fix belongs before Reflect.set?

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        "use strict";
        const proxy = new Proxy({}, { set(target, key, value, receiver) { Reflect.set(target, key, value, receiver); } });
        try { proxy.answer = 42; } catch (error) { console.log(error.name); }

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · PracticeCall with an argument list

          Predict the line printed by Reflect.apply.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function add(prefix, a, b) { console.log(prefix + (a + b)); }
          Reflect.apply(add, null, ["total:", 2, 5]);

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            7 QUESTIONS
            Reflect quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which statement best describes Reflect?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the failed Reflect definition print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const locked = Object.preventExtensions({});
              console.log(Reflect.defineProperty(locked, "x", { value: 1 }));

              Choose an answer to see the explanation.

            3. Question 3 of 7Which Reflect method is the function form of the in operator?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does this ownKeys order print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const s = Symbol("s");
              const obj = { 10: "ten", a: 1, 2: "two" };
              Object.defineProperty(obj, "hidden", { value: true });
              obj[s] = 3;
              console.log(Reflect.ownKeys(obj).map((k) => typeof k === "symbol" ? k.toString() : k).join(","));

              Choose an answer to see the explanation.

            5. Question 5 of 7Why return Reflect.set(...args) from a proxy set trap?

              Choose an answer to see the explanation.

            6. Question 6 of 7What does Reflect.apply print here?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function join(a, b) { console.log(this.prefix + a + b); }
              Reflect.apply(join, { prefix: "#" }, [2, 3]);

              Choose an answer to see the explanation.

            7. Question 7 of 7What does Reflect.construct's third argument control?

              Choose an answer to see the explanation.

            Key takeaways

            • Reflect exposes JavaScript’s object operations as plain functions.
            • There are 13 Reflect methods, matching the 13 proxy traps.
            • Several mutating Reflect methods return booleans instead of throwing for ordinary operation failure.
            • Use Reflect.get and Reflect.set with the receiver when forwarding proxy traps.
            • Reflect.ownKeys returns integer-like strings, other strings, then symbols, including non-enumerable keys.
            • Reflect.construct can set new.target with its third argument.

            Reflect is the standard function-based API for performing and forwarding JavaScript object operations.

            Up next: Well-known symbols.

            CompleteFrontend Clear concepts. Working examples.