JavaScript ES6 Reflect API
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:
- 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 attributesconsole.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.