completefrontend
Open lab My progress
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
    Match jobs to methodsName the Reflect method for common object jobs, like reading, writing, and deleting a property.
  • 02
    Pass proxy traps on safelyCall the matching Reflect method inside a trap, and return its true or false answer.
  • 03
    Keep this rightExplain why Reflect.get(target, key, receiver) matters when a getter runs.

Reflect does object jobs with plain functions

You already know many ways to work with an object:

  • read a property, like cart.tea
  • check for a key with in, like "tea" in cart
  • remove a key with delete
  • make a new object with new
  • add a property with Object.defineProperty

Reflect is a built-in object that holds functions for these same jobs. Each job becomes a plain function call, like Reflect.has(cart, "tea").

Why use a function when the short syntax works? The main reason is a proxy. A proxy is an object that stands in front of another object, called the target. You met proxies in the Proxy lesson. A proxy has traps: functions that catch an action, like a read or a write. A trap often does one small extra thing, like writing a log. Then it wants to do the normal action. Reflect has one function for each normal action, so the trap can call it.

Real-life analogyReflect is a service desk

Picture a big building. Most small jobs happen by hand: you open a door, read a name plate, or take down a sign. The building also has a service desk. At the desk, you fill in a clear form for the same jobs, and the desk does them for you. The desk often answers with a simple yes or no.

In real life: Ask the desk whether a room exists
In JavaScript: Reflect.has(target, key)
In real life: Ask the desk to remove a room
In JavaScript: Reflect.deleteProperty(target, key)
In real life: Ask the desk to set up a new room and say if it worked
In JavaScript: Reflect.defineProperty(target, key, descriptor)
In real life: The desk answers yes or no, calmly
In JavaScript: Many Reflect methods that change an object return true or false
The main idea

Reflect is a built-in object with 13 methods. Each method does one basic object job, like reading, writing, or deleting a property. The 13 methods match the 13 proxy traps, one for one. Use Reflect when you want an object job as a function call, most of all inside proxy traps.

Start with a normal object. Three Reflect calls check for a key, delete it, and check again.

Check, delete, and check againPop out in the code editor (opens in a new tab)JavaScript
const cart = { tea: 2 };
console.log(Reflect.has(cart, "tea"));
console.log(Reflect.deleteProperty(cart, "tea"));
console.log(Reflect.has(cart, "tea"));

In plain words, line by line:

  1. Line 1 makes a small cart object with one key, tea.
  2. Line 2 asks: does cart have a key named tea? It does, so it prints true.
  3. Line 3 deletes tea. The delete works, so it prints true.
  4. Line 4 asks again. The key is gone, so it prints false.

In this lesson you will:

  • compare Reflect with Object methods
  • keep a getter's this right when a proxy passes a read on
  • pass proxy traps on to Reflect
  • list every key of an object, in order
  • call functions and constructors with Reflect.apply and Reflect.construct

The 13 Reflect methods, one per object job

SORTER

Reflect is not magic. Each method is a named function for a job JavaScript already knows how to do. Here are all 13: apply, construct, defineProperty, deleteProperty, get, getOwnPropertyDescriptor, getPrototypeOf, has, isExtensible, ownKeys, preventExtensions, set, and setPrototypeOf.

Read each row of the next table from left to right: the job, the Reflect method that does it, and what the method gives back.

Common Reflect methods and what they return
The jobReflect methodWhat it gives back
Read a propertyReflect.get(target, key, receiver?)The value. The optional receiver becomes this if a getter runs.
Write a propertyReflect.set(target, key, value, receiver?)true if the write worked, false if it was blocked.
Check for a keyReflect.has(target, key)true or false, like the in operator.
Delete a keyReflect.deleteProperty(target, key)true or false, like delete target[key].
List every own keyReflect.ownKeys(target)An array of string and symbol keys, hidden ones too.
Call a function, or make an object with itReflect.apply / Reflect.constructWhat the function returns, or the new object.

Five methods change an object and answer true or false. The answer tells you whether the change worked:

  • defineProperty
  • set
  • deleteProperty
  • preventExtensions
  • setPrototypeOf

This answer is most useful inside proxy traps. A set trap, for example, must give back true or false.

A false answer does not mean Reflect never throws. Reflect still throws a TypeError in these cases:

  • The target is not an object, for example the number 1.
  • Reflect.apply gets something that is not a function.
  • A proxy breaks one of its fixed rules. The Proxy lesson calls these rules invariants.

The next table names each of the five methods and the case where it returns false.

When each method returns false
Reflect methodWhen does it return false?
Reflect.definePropertyWhen the property can't be added, for example on an object that can't grow.
Reflect.setWhen the write is blocked. For example, the property is read-only, has a getter but no setter, or a proxy trap refuses.
Reflect.deletePropertyWhen the property is locked with configurable: false.
Reflect.preventExtensionsWhen a proxy trap refuses. A plain object always answers true.
Reflect.setPrototypeOfWhen the change isn't allowed, for example on an object that can't grow.
Sort each job by kind
  • Read user.name and keep the getter's this right
  • Do user.name = value from inside a trap
  • Check whether name in user is true
  • List string keys, symbol keys, and hidden keys
  • Add a property with flags and get true or false
  • Try to change an object's prototype
  • Call a function with a chosen this and an array of arguments
  • Use a constructor with a different new.target
Try it yourself
0 of 8 correct

Drag each card to the kind of job its Reflect method does.

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

Reflect compared with Object methods

STEP THROUGH

Some Object methods act differently from their Reflect twins. Two differences matter most:

  • When the job fails. Object.defineProperty throws an error. Reflect.defineProperty returns false.
  • When the target is not an object. Object.getPrototypeOf(1) treats the number like a number object and returns Number.prototype. Reflect.getPrototypeOf(1) throws a TypeError, because Reflect only accepts objects.

Step through the first difference. Line 2 uses Object.preventExtensions, which stops an object from growing: no new properties can be added to it. Then the code tries to add id two ways.

Object throws, Reflect answers false
Step 0 of 5Ready
Your turn: follow the blue line

Step through the same failed job with Object and with Reflect. Guess first: which one throws, and which one returns false?

Running in
  1. script
Next: line 2
"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);
CallStoreChangeResultBlue line: runs next. 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.
Left: Object.defineProperty tries to add id: 1 to the locked cart and throws a TypeError. Right: Reflect.defineProperty tries the same and returns false. Both locked carts stay empty.Object.definePropertyid: 1TypeErrorit throwslockedno id addedReflect.definePropertyid: 1falseit returnslockedno id added
Both calls try to add id to an object that can't grow. Object.defineProperty throws a TypeError; Reflect.defineProperty just returns false.

Here are three more pairs:

  • Reflect.has does the same job as in.
  • Reflect.deleteProperty does the same job as delete.
  • Reflect.ownKeys lists more keys than Object.keys.
Four Reflect calls on one object
Check, delete, and list keysPop 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));
What it printsin a console

Lines 6 and 7 print true. Line 8 lists visible, hidden, and Symbol(tag). Line 9 lists only visible.

Try it yourself
Compare each call with the syntax it matches.

Reflect.has does the job of in. Reflect.deleteProperty does the job of delete. Reflect.ownKeys lists more keys than Object.keys. Reflect still throws a TypeError if you give it a number or a string instead of an object.

A quick map of common jobs, before the receiver and proxy labs.

Next, see two kinds of failure side by side: a thrown error, and a false answer.

A thrown error, then a false answerPop out in the code editor (opens in a new tab)JavaScript
try {
  Reflect.getPrototypeOf(1);
} catch (error) {
  console.log(error.name);
}
const box = {};
Object.defineProperty(box, "id", { value: 1, configurable: false });
console.log(Reflect.deleteProperty(box, "id"));

In plain words, line by line:

  1. Line 2 passes the number 1, but Reflect needs an object. It throws a TypeError, and line 4 prints its name.
  2. Line 7 adds an id property. configurable: false locks it, so it can't be deleted.
  3. Line 8 tries to delete id. The target is a real object, so nothing throws. The delete fails, so Reflect returns false.

So the two failures mean different things. false means a fair try that didn't work. A TypeError means the call itself was wrong.

Here is the code from the lab as a plain block, so you can paste it into a console.

Four calls on one objectPop 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));

Line 7 returns true even though missing never existed. After the call, the key is not there, and that counts as success.

Receivers: who is asking?

INTERACTIVE

First, a reminder about getters. A getter is a function that runs when you read a property. Inside the getter, this is the object you read from.

The receiver is the object that becomes this when a getter or setter runs. When you write obj.value, the receiver is obj.

Most of the time, the object that holds the getter is the object you read from. But they can be different:

  • With a prototype, the getter can live on the prototype, while you read from a child object.
  • With a proxy, the getter is found through the target, while you read from the proxy.
Real-life analogyThe receiver is who is asking

A person at a counter asks, "What does my name badge say?" The clerk passes the question to a back office. If the clerk passes on the exact request slip, the back office reads the right badge. If the clerk writes a new slip with their own name, the back office reads the wrong badge.

In real life: A clerk answers a question for the person at the counter
In JavaScript: A getter runs with this set to the receiver
In real life: The clerk passes the question on, but writes their own name on the slip
In JavaScript: target[key] can run the getter with the wrong this
In real life: The clerk passes on the exact request slip
In JavaScript: Reflect.get(target, key, receiver) keeps the person who asked

Step through a proxy that passes a getter read on. Pick line 12 first: plain target[key], or Reflect.get(target, key, receiver).

Read a getter through a proxy, with or without the receiver
Step 0 of 6Ready
Your turn: follow the blue line

Pick line 12, then step. Both choices print the same value here. The steps show what this is inside the getter.

Running in
  1. script
Next: line 2
"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);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Choose line 12 before you step

Both choices print the same value here. Only the Reflect choice keeps the proxy as this inside the getter.

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.

The next example makes the difference easy to see. Each proxy writes every key it is asked for into a list named reads.

With the receiver, the trap sees more readsPop out in the code editor (opens in a new tab)JavaScript
const reads = [];
const profile = { name: "Asha", get label() { return this.name; } };
const user = Object.create(profile);
const naive = new Proxy(user, { get(target, key) { reads.push(String(key)); return target[key]; } });
console.log(naive.label, reads.join(","));
reads.length = 0;
const forwarded = new Proxy(user, { get(target, key, receiver) { reads.push(String(key)); return Reflect.get(target, key, receiver); } });
console.log(forwarded.label, reads.join(","));

In plain words, line by line:

  1. Line 2: profile has a name and a label getter that returns this.name.
  2. Line 3: user is a new, empty object whose prototype is profile.
  3. Line 4: the naive proxy writes down each key, then reads it with target[key].
  4. Line 5 prints Asha label. The getter ran with this set to user, so its name read skipped the proxy.
  5. Line 6 empties the list.
  6. Line 7: the forwarded proxy writes down each key, then reads it with Reflect.get(target, key, receiver).
  7. Line 8 prints Asha label,name. The getter ran with this set to the proxy, so its name read went through the trap too.
Left: naive.label uses target[key], so inside the getter this is user and the trap log shows only label. Right: forwarded.label uses Reflect.get with the receiver, so this is the forwarded proxy and the trap log shows label,name.naive.labeluses target[key]userthistrap loglabelforwarded.labeluses Reflect.get + receiverforwardedthistrap loglabel,name
Both print Asha. Only the right side keeps the proxy as this, so its trap also sees the name read.

Here both proxies print the same name. The difference matters when:

  • the getter does more work with this
  • a setter checks a value using this
  • the proxy must see every read

So inside a proxy get trap, write return Reflect.get(target, key, receiver).

Pass each trap on to its Reflect method

STEP THROUGH

A proxy trap often does two things: it writes a note in a log, then it does the normal job. The simplest safe way to do the normal job:

  • Take every argument the trap gets with ...args. This rest syntax collects all the arguments into one array named args.
  • Pass the same arguments to the Reflect method with the same name, like Reflect.get(...args). The ... here spreads the array back out into separate arguments.
A logging proxy passes each job on to Reflect
Step 0 of 7Ready
Your turn: follow the blue line

Follow a logging proxy that passes each job on to Reflect. Watch the answer that Reflect.set gives back.

Running in
  1. script
Next: line 2
"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(", "));
CallStoreChangeResultBlue line: runs next. 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.
proxy.count = proxy.count + 1. First the get trap passes the read on with Reflect.get. Then the set trap passes the write on with Reflect.set. The target cart ends with count: 1, and the log holds get:count, then set:count.proxy.count = proxy.count + 1get trapset trap1. Reflect.get2. Reflect.setcount: 1targetlogget:countset:count
The line reads count first, then writes it. Each trap writes in the log, then passes the work on to the matching Reflect method.
Always return the answer from Reflect.set

A set trap must return true or false. In strict mode, if it returns false, or forgets to return and so gives undefined, the assignment throws a TypeError. return Reflect.set(...args) does the normal write and returns its true or false in one line.

A trap can also refuse a write. This set trap refuses a negative balance.

A set trap that refuses a negative balancePop out in the code editor (opens in a new tab)JavaScript
const account = { balance: 10 };
const safe = new Proxy(account, {
  set(target, key, value, receiver) {
    if (key === "balance" && value < 0) return false;
    return Reflect.set(target, key, value, receiver);
  }
});
console.log(Reflect.set(safe, "balance", 20));
console.log(Reflect.set(safe, "balance", -1));
console.log(account.balance);

In plain words, line by line:

  1. Line 4: if the key is balance and the new value is below 0, the trap returns false and writes nothing.
  2. Line 5: any other write goes on to Reflect.set, which does the write and returns true.
  3. Line 8 writes 20. The trap accepts it, so it prints true.
  4. Line 9 writes -1. The trap refuses it, so it prints false.
  5. Line 10 prints 20. The refused write never reached account.

Lines 8 and 9 call Reflect.set on the proxy, so a refusal comes back as false, not as an error. The code that made the call can decide what to do next, for example throw its own error.

Reflect.ownKeys lists every key

INTERACTIVE

An object's own keys are the keys stored on the object itself, not on its prototype. Object.keys lists only some of them:

  • It lists string keys only, never symbol keys.
  • It lists enumerable keys only. An enumerable key is one that shows up in loops and key lists. A key added with Object.defineProperty is not enumerable unless you ask for it.

Reflect.ownKeys lists every own key, enumerable or not, in this order:

  1. Number keys: keys that look like whole numbers, such as "3" and "20", from smallest to biggest.
  2. String keys: all other strings, in the order they were added.
  3. Symbol keys, in the order they were added.
Key order lab
Which keys does each call list?Pop 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 real run always uses Reflect.ownKeys. The buttons only hide parts of its list, so you can compare it with Object.keys. Number keys come first, smallest first.

Compare every own key with the enumerable string keys. Reset shows the full Reflect list again.
Reflect.ownKeys(record) gives 3, 20, name, hidden, Symbol(id): number keys from small to big, then string keys in the order added, then symbol keys. Object.keys(record) gives only 3, 20, name.Reflect.ownKeys(record)320namehiddenSymbol(id)number keyssmall to bigstring keysorder addedsymbol keysorder addedObject.keys(record)320nameno hidden, no symbol
Reflect.ownKeys lists every own key: number keys, then string keys, then symbols. Object.keys leaves out hidden and the symbol.

That fixed order is why an array's indexes always come out as 0, 1, 2, and so on. Symbol keys always come last. If symbol keys are new to you, review the Symbols lesson first.

Sometimes you want only one kind of key. Two Object methods split the list.

Only string keys, then only symbol keysPop out in the code editor (opens in a new tab)JavaScript
const item = { name: "tea" };
Object.defineProperty(item, "hidden", { value: true });
const id = Symbol("id");
item[id] = 1;
console.log(Object.getOwnPropertyNames(item).join(","));
console.log(Object.getOwnPropertySymbols(item).map(String).join(","));

In plain words, line by line:

  1. Line 2 adds hidden with Object.defineProperty, so it is not enumerable.
  2. Lines 3 and 4 add a symbol key.
  3. Line 5: Object.getOwnPropertyNames lists every own string key, hidden ones too. It prints name,hidden.
  4. Line 6: Object.getOwnPropertySymbols lists only symbol keys. It prints Symbol(id).

Use these when you want one kind of key. Use Reflect.ownKeys when you want both kinds, in the standard order.

Reflect.apply and Reflect.construct

INTERACTIVE

Reflect.apply(fn, thisArg, args) calls a function. It takes three things:

  • fn: the function to call
  • thisArg: the value for this inside the function
  • args: an array of arguments

It does the same job as fn.apply(thisArg, args), which you met in the call, apply & bind lesson.

Reflect.construct(Target, args, NewTarget) does the job of new Target(...args). The third argument, NewTarget, is optional. When you pass it, two things change:

  • Inside the constructor, new.target is NewTarget. new.target tells a constructor which function new was used with.
  • The new object's prototype is NewTarget.prototype.

The lessons on constructors and new cover these ideas. Two rules still hold:

  • Target must be something you can use with new. An arrow function can't be, and NewTarget can't change that.
  • If NewTarget.prototype is not an object, the new object gets Object.prototype as its prototype instead.
Apply and construct lab
Call a function, then build an objectPop 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
  • item.createdBySpecial
  • Prototype is Special.prototype?true
Try it yourself
Read the three results from the real run.

Reflect.apply calls total with an array of arguments. Reflect.construct runs Base, but its third argument makes new.target and the prototype come from Special.

The code sets createdBy to plain text. It doesn't read function names, because tools that shrink code for the web can rename functions.

Next, compare Reflect.apply with the older apply method.

Reflect.apply next to fn.applyPop out in the code editor (opens in a new tab)JavaScript
function add(a, b) {
  return this.base + a + b;
}
const context = { base: 10 };
console.log(Reflect.apply(add, context, [2, 3]));
console.log(add.apply(context, [2, 3]));

Both lines call add with this set to context and the arguments 2 and 3. Both print 15, which is 10 + 2 + 3. Reflect puts the function, the this value, and the arguments in three separate slots. That is handy when a helper passes a call on.

Here is the code from the lab again as a plain block.

The apply and construct codePop 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 in libraries. A library is code written for other programmers to reuse. Common places:

  • proxies that check values before they are saved
  • objects that tell the page when their data changes
  • test doubles: stand-in objects used in tests
  • frameworks that add a small extra step to normal object behavior
Checking proxy

Check a value in set. If it is fine, return Reflect.set(...args).

Logging proxy

Log each get, set, and deleteProperty, then pass it on to the matching Reflect method.

Safe property adder

Try to add a property with Reflect.defineProperty, and check whether it returned false.

Save-to-text tool

Use Reflect.ownKeys when hidden keys or symbol keys must be saved too.

The habit is simple. Inside a proxy trap, when you want the normal behavior, call the matching Reflect method. Then add only the extra step you need.

Outside proxies, the short syntax is often clearer. Write cart[key] for a single read, and delete cart[key] for a single delete. Choose Reflect when a helper or proxy must pass on the exact job and report whether it worked.

Common misconceptions

  • "Reflect never throws." Many methods return false when the job fails. But Reflect still throws a TypeError when it needs an object and gets something else, like a number.
  • "Reflect is only for proxies." Proxies are the main use. The function forms also help any helper that gets the job to do as data.
  • "Reflect.ownKeys is the same as Object.keys." Reflect.ownKeys also lists keys that are not enumerable, and symbol keys. Object.keys leaves both out.
  • "The receiver is always the target." With inherited getters and proxy traps, the receiver can be the object that was first asked, such as the proxy.
  • "Reflect.construct is just new without the word new." Its third argument also sets new.target and the new object's prototype.
  • "A set trap can skip the return." Then it returns undefined, which counts as failure. In strict mode, the assignment throws a TypeError.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upWhich one throws: Object or Reflect?

Read the code. What are the two lines it prints?

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

    The getter lives on the prototype. What does this print, and why is it the user's name?

    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

      What does the code print? The keys are joined with |.

      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? Which one word belongs before Reflect.set to fix it?

        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 a list of arguments

          What line does Reflect.apply print?

          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 sentence best describes Reflect?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the failed Reflect call 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 does the same job as the in operator?

              Choose an answer to see the explanation.

            4. Question 4 of 7What order does this 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 write return Reflect.set(...args) in 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 the third argument of Reflect.construct control?

              Choose an answer to see the explanation.

            Key takeaways

            • Reflect does basic object jobs with plain functions.
            • It has 13 methods, one for each of the 13 proxy traps.
            • Five methods that change an object return true or false when the job works or fails, instead of throwing.
            • Reflect still throws a TypeError when it needs an object and gets something else.
            • Inside proxy traps, pass receiver on to Reflect.get and Reflect.set, so this stays right.
            • Reflect.ownKeys lists number keys, then other string keys, then symbol keys, hidden keys included.
            • Reflect.construct can set new.target with its third argument.

            Reflect is JavaScript's built-in set of functions for doing basic object jobs, and for passing them on.

            Up next: Well-known symbols.

            CompleteFrontend Clear concepts. Working examples.