JavaScript ES6 Reflect API

Amir Mustafa
8 min readMay 12, 2021

--

Why ES6 — Reflect API is important? Let us understand it.

What is the Reflect API?

The Reflect API could be described as a collection or “central place” which houses all kind of object and function related functions (for creation, property management etc.). Some of the functionalities added on the Reflect object where available before on the Object object.

But the goal for the future is, to have on central place to store all those methods — the Reflect Object/ API.
Therefore, the Reflect API provides useful methods to create, manipulate and query objects and functions in your JavaScript project.

Some points to note:

  1. Reflect API deals with Meta programming.

Metaprogramming means that you’re able to change (parts of) the behavior of the underyling language — JavaScript in this case. This of course is a powerful feature as it allows you to influence the way your code is executed. The Reflect API (like Symbols and Proxies) are important additions which help you with Metaprogramming — something that wasn’t really possible in JavaScript before.

2. Previously JS had this but it was scattered. Like delete has delete method, create has create method seperately. Now it is all bundled together (i.e. all in one).

3. Together with Proxy API, it gives more facility

4. It offers us some additional utility — like we will see creating object and setting its prototype at the same time and many more functions.

5. This is not a constructor function. So it is called without new keyword (Similar to object key). All methods are static here.

List of Reflect Methods:

1. Reflect.construct():

→ We already know many ways to create JS object — object literal, constructor function, Object.create(), etc

→ We can create object using construct method.

TRICK (When to use):

When you want to create object and assign different prototype at once.

class Person {  constructor(name) {    this.name = name  }}let person = Reflect.construct(Person, ['Amir']); // parameterconsole.log(person);

→ It also has optional 3rd parameter, if you wish to change the prototype

class Person {  constructor(name) {    this.name = name  }}function TopObj() {  this.age = 27;}// With 3rd parameter: Person prototype changed to TopObjlet person = Reflect.construct(Person, ['Amir'], TopObj);console.log(person.__proto__ === Person.prototype);  // falseconsole.log(person.__proto__ === TopObj.prototype);  // true

2. Reflect.apply():

→ This method is called when we want to call a method in which this pointing changes from global object

→ This is somewhat similar to call() and apply() of JavaScript

TRICK (When to use):
Whenever you want to execute a method and change its this pointer to different object.

Eg1:

class Person {  constructor(name, age) {    this.name = name;    this.age = age;  }  greet() {    console.log("My name is " + this.name);  }}// Create objectlet person = Reflect.construct(Person, ["Amir", 28]);// Calling greet() and this points to person obj// 1st para = function to call// 2nd para = obj where this will point// 3rd para = passed args passed to greet function// person.greet(). // Regular Way - call greet()Reflect.apply(person.greet, person, []); 

→ Eg2 If we pass the second as empty object or pass as some other object it will refer to that

Eg3: Passing parameter to method (3rd parameter)

3. Reflect.getPrototypeOf():

→ We can set prototype by this method

→ This method is similar to __proto__

→ __proto__ was not the standard way to write in code, there should be some method. Hence getPrototypeOf()

class Person {  constructor() {    this.name = "Amir";  }}let person = new Person;// this is equivalent to person.__proto__console.log(Reflect.getPrototypeOf(person));   // prototype is pointing to Personconsole.log(Reflect.getPrototypeOf(person) === Person.prototype) // true

Eg2: Adding/Assigning some keys in prototype:

class Person {  constructor() {    this.name = "Amir";  }}let person = new Person;Person.prototype.age = 28; // assigning some key in prototype// this is equivalent to person.__proto__console.log(Reflect.getPrototypeOf(person));

4. Reflect.setPrototypeOf():

→ To set a prototype we use this method

→ Earlier we used.

Person.prototype.age = 28;

Eg1:

class Person {  constructor() {    this.name = "Amir";  }}let proto = {age: 30};let person = new Person; // assigning some key in prototypePerson.prototype.age = 28;Reflect.setPrototypeOf(person, proto);// this is equivalent to person.__proto__ // Prototype changedconsole.log(Reflect.getPrototypeOf(person));

Eg2:

5. Reflect.get():

→ We can access objects with Reflect

→ Earlier:

let obj = {name: 'Amir'};
console.log(obj.name); // This was used

→ Now we have explicit functions for the same:

Eg1:

class Person {  constructor(name, age) {    this.name = name;    this.age = age;  }}// let person = Reflect.construct(Person, ["Amir", 28]);let person = new Person("Amir", 28);
// Get properties - Very useful in fetching dynamic attributes
console.log(Reflect.get(person, 'name'));

Eg2: Same example with getters:

→ For getter we write _ before property name

class Person {  constructor(name, age) {    this._name = name;    this.age = age;  }// Using getter - always give _property for getter - works same  get name() {    return this._name;  }}let person = new Person("Amir", 28);// Get properties - Very useful in fetching dynamic attributesconsole.log(Reflect.get(person, 'name'));

TRICK (When to use):

Whenever there are dynamic keys. Suppose you are fetching lists from db or API. This method is best with Reflect.get()

6. Reflect.set():

→ We can also update the property

→ This works for already existing property and not for newly created keys

Earlier:

let obj = {name: "Amir"};
obj.name = "Max";

With Reflect

class Person {  constructor(name, age) {    this.name = name;    this.age = age;  }}// let person = Reflect.construct(Person, ["Amir", 28]);let person = new Person("Amir", 28);// Set propertyReflect.set(person, 'name', "Max"); // Get properties - Very useful in fetching dynamic attributesconsole.log(Reflect.get(person, 'name'));

→ Both get and set methods have optional 3rd parameter (for get) and 4th parameter (for set).

→ The object which we write in the 3rd parameter is where this will be pointing to.

Eg1. get method — optional third parameter

class Person {  constructor(name, age) {    this._name = name;    this.age = age;  }  get name() {    return this._name;  }}// let person = Reflect.construct(Person, ["Amir", 28]);let person = new Person("Amir", 28);// Set propertyReflect.set(person, 'name', "Max");// This is optional 3rd parameter
let mum = {
_name: "Amaira"};console.log(Reflect.get(person, 'name', mum));

Eg2: set method — optional 4th parameter

class Person {  constructor(name, age) {    this._name = name;    this.age = age;  }  get name() {    return this._name;  }  set name(value) {    this._name = value  }}// let person = Reflect.construct(Person, ["Amir", 28]);let person = new Person("Amir", 28);let mum = {  _name: "Amaira"};// Set propertyReflect.set(person, 'name', "Max", mum); // this will override Max in mum obj itself// Get properties - Very useful in fetching dynamic attributesconsole.log(Reflect.get(person, 'name', mum));  // Max

7. Reflect.has():

→ Checks if the propery is there or not

console.log(Reflect.has(person, 'age'));

8. Reflect.ownKeys():

→ This will give list of keys present in the object

console.log(Reflect.ownKeys(person));

9. Create property — Object.defineProperty() and Reflect.defineProperty():

→ With Reflect.set() — We can only update property. For creating new property we have these methods.

A. ES5 JavaScript defineProperty (i.e. Object.defineProperty()):

→ If you are somehow not familiar with this let me refresh this here.

→ This is just to create a new object with some configurations — like whether. object name can be modified or enumerable (i.e loopable), etc

→ By default values are read only

Eg1:

const object1 = {};Object.defineProperty(object1, 'property1', {  value: 42,  writable: false});object1.property1 = 77;// no error is thrown but value will not be overridden
console.log(object1.property1);
// expected output: 42

Eg2:

Object.defineProperty(obj, 'key', {  enumerable: false,   // is loopable  configurable: false,//Property can be changed or not after created  writable: true,      // Read only or can be modified  value: 'static'     // Value of this key});
console.log(object1.key);
// expected output: static

B. Reflect.defineProperty()

→ This is same way to the JS define property. Just that we can define from Reflect as well now

TRICK (When to use):
When you want to create object with read only

Eg1:

// Reflect ES6 define propertyclass Person {  constructor(name, age) {    this.name = name;    this.age = age;  }}let person = new Person("Amir", 28);
// Define property - by default it will be read only - non writable
Reflect
.defineProperty(person, 'hobbies', {
value: ["Sports", "Cooking"]});console.log(person.hobbies); // ["Sports", "Cooking"]// NOTE: printing console.log(person); will not show hobbies

Eg2:

10. Reflect.deleteProperty():

→ Earlier in JS there was just a keyword was there for deleting a property and not evening a function like add or update in JS

delete person.hobbies; // one keyword for deleting props JS Way

→ In ES6:

Reflect.deleteProperty(person, 'hobbies'); // Reflect Way (Delete a property)console.log(person.hobbies); // undefined

11. Restricting adding properties

→ There are two Reflect functions for this:

a. Reflect.preventExtensions(person); — You will not be able to modify after this method

b. Reflect.isExtensible(person) — checks if prevent extension is applied or not. O/P is boolean

Eg.

// Reflect ES6 define propertyclass Person {  constructor(name, age) {     this.name = name;     this.age = age;  }}let person = new Person("Amir", 28);
//Restrict extension:
Reflect.preventExtensions(person);// No more extension can be addedconsole.log(Reflect.isExtensible(person)); // boolean-Checks if objects can be extended
// adding new property --> will not work as restricted adding new above
Reflect.defineProperty(person, 'hobbies', {value: ["Sports", "Cooking"],writable: true});console.log(person.hobbies);

→ I hope you got the understanding of Reflect. Normally some of the methods were scattered earlier. Now all in one central place Reflect.

Thank you for being till the end 🙌 . If you enjoyed this article, or learned something new, support me by clicking the share button below to reach more people and/or give me a follow on Twitter to see some other tips, articles, and things I learn and share there.

--

--

Amir Mustafa
Amir Mustafa

Written by Amir Mustafa

JavaScript Specialist | Consultant | YouTuber 🎬. | AWS ☁️ | Docker 🐳 | Digital Nomad | Human. Connect with me on https://www.linkedin.com/in/amirmustafa1/

No responses yet