JavaScript Reflection
Summary: in this tutorial, you will learn about the JavaScript reflection and Reflect API in ES6.
What is reflection
In computer programming, reflection is the ability of a program to manipulate variables, properties, and methods of objects at runtime.
Prior to ES6, JavaScript already has reflection features even though they were not officially called that by the community or the specification. For example, methods like Object.keys(), Object.getOwnPropertyDescriptor(), and Array.isArray() are the classic reflection features.
ES6 introduces a new global object called Reflect that allows you to call methods, construct objects, get and set properties, manipulate and extend properties.
The Reflect API is important because it allows you to develop programs and frameworks that are able to handle dynamic code.
Reflect API
Unlike the most global objects, the Reflect is not a constructor. It means that you cannot use Reflect with the new operator or invoke the Reflect as a function. It is similar to the Math and JSON objects. All the methods of the Reflect object are static.
Reflect.apply()– call a function with specified arguments.Reflect.construct()– act like thenewoperator, but as a function. It is equivalent to callingnew target(...args).Reflect.defineProperty()– is similar toObject.defineProperty(), but return a Boolean value indicating whether or not the property was successfully defined on the object.Reflect.deleteProperty()– behave like thedeleteoperator, but as a function. It’s equivalent to calling thedelete objectName[propertyName].Reflect.get()– return the value of a property.Reflect.getOwnPropertyDescriptor()– is similar toObject.getOwnPropertyDescriptor(). It returns a property descriptor of a property if the property exists on the object, orundefinedotherwise.Reflect.getPrototypeOf()– is the same asObject.getPrototypeOf().Reflect.has()– work like theinoperator, but as a function. It returns a boolean indicating whether an property (either owned or inherited) exists.
Reflect.isExtensible()– is the same asObject.isExtensible().Reflect.ownKeys()– return an array of the owned property keys (not inherited) of an object.Reflect.preventExtensions()– is similar toObject.preventExtensions(). It returns a Boolean.Reflect.set()– assign a value to a property and return a Boolean value which is true if the property is set successfully.Reflect.setPrototypeOf()– set the prototype of an object.
Let’s take some examples of using the Reflect API:
Creating objects: Reflect.construct()
The Reflect.construct() method behaves like the new operator, but as a function. It is equivalent to calling the new target(...args) with the possibility to specify a different prototype:
Reflect.construct(target, args [, newTarget])
Code language: CSS (css)
The Reflect.construct() returns the new instance of the target, or the newTarget if specified, initialized by the target as a constructor with the given array-like object args. See the following example:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
};let args = ['John', 'Doe'];
let john = Reflect.construct(
Person,
args
);
console.log(john instanceof Person);
console.log(john.fullName); // John Doe
Code language: JavaScript (javascript)
Output
true
John Doe
Code language: JavaScript (javascript)
In this example:
- First, define a class called
Person. - Second, declare an
argsarray that contains two strings. - Third, create a new instance of the
Personclass using theReflect.construct()method. Thejohnobject is an instance of thePersonclass so it has thefullNameproperty.
Calling a function: Reflect.apply()
Prior to ES6, you call a function with a specified this value and arguments by using the Function.prototype.apply() method. For example:
let result = Function.prototype.apply.call(Math.max, Math, [10, 20, 30]);
console.log(result);
Code language: JavaScript (javascript)
Output:
30
This syntax is quite verbose.
The Reflect.apply() provides the same feature as the Function.prototype.apply() but less verbose and easier to understand:
let result = Reflect.apply(Math.max, Math, [10, 20, 30]);
console.log(result);
Code language: JavaScript (javascript)
Here is the syntax of the Reflect.apply() method:
Reflect.apply(target, thisArg, args)
Code language: JavaScript (javascript)
Defining a property: Reflect.defineProperty()
The Reflect.defineProperty() is like the Object.defineProperty(). However, it returns a Boolean indicating whether or not the property was defined successfully instead of throwing an exception:
Reflect.defineProperty(target, propertyName, propertyDescriptor)
Code language: JavaScript (javascript)
See the following example:
let person = {
name: 'John Doe'
};if (Reflect.defineProperty(person, 'age', {
writable: true,
configurable: true,
enumerable: false,
value: 25,
})) {
console.log(person.age);
} else {
console.log('Cannot define the age property on the person object.');
}
Code language: JavaScript (javascript)
In this tutorial, you have learned about JavaScript reflection and the Reflect API which contains a number of reflective methods.