
Object reflection is an language ability to able to inspect and manipulate object properties at runtime. JavaScript already had been supporting APIs for object reflection but these APIs were not organized under a namespace and also they threw exception when they fail to complete an operation. This made it difficult to write scripts involving object reflection.
ES2015 introduces a new object referred as Reflect
which exposes methods for object reflection. These new methods don’t throw exception on failure rather they return error, which makes it easy to write code involving object reflection.
The Reflect
Object
The Reflect
object is not a constructor that is it we cannot use it with new
operator. It’s a plain object that exposes the methods related to object reflection as its own properties. Reflect
is the only object introduced by ES2015 Reflect API.
Only couple of major browsers support the Reflect
object at the time of writing this article. Check out the compatibility here. We can use harmony-reflect polyfill created by Tom Van Cutsem to use Reflect in non-compatible browsers. If we are using a transpiler to convert ES2015 to ES5 then we don’t need the polyfill.
Reflect object exposes in total 14 methods for object reflection. Here is the list and explanation of each of the methods with examples:
Reflect.get(object, property[, this])
Reflect.get
is used to retrieve value of an object property. The first parameter is the reference to the object and second parameter is the property name. If we are retrieving value of an accessor property then we can provide a third parameter which is the value of this
keyword inside the get
function.
Here is an example to demonstrate Reflect.get
method:
var name = Reflect.get(obj, "name");
console.log(name); //Output "narayan"
The Reflect.get()
method works the same way as the dot and brackets operators for retrieving value of an object property. The only reason why you would want to use Reflect.get()
is when you want to retrieve value of an accessor property by providing a custom value for the this
keyword inside the get
function. manually.
Here is an example to demonstrate Reflect.set
method:
Reflect.set(obj, "name", "narayan");
console.log(obj.name); //Output "narayan"
The Reflect.set()
method works the same way as the dot and brackets operators for setting value of an object property. The only reason why you would want to use Reflect.set()
is when you want to set value of an accessor property by providing a custom value for the this
keyword inside the set
function. manually.
Reflect.defineProperty(object, property, descriptor)
Reflect.defineProperty
is used to define an object property. Its same as the Object.defineProperty
method. Reflect.defineProperty
takes the same three arguments as the Object.defineProperty
method.
Here is an example to demonstrate Reflect.defineProperty
:
Reflect.defineProperty(obj, "name", {value: "narayan"});
console.log(obj.name); //Output "narayan"
Reflect.deleteProperty(object, property)
Reflect.deleteProperty
is used to delete an object property. It’s same as the delete
operator. The first argument is the object reference and second argument is the property name.
Here is an example to demonstrate Reflect.deleteProperty
:
Reflect.deleteProperty(obj, "name");
console.log(obj.name); //Output "undefined"
Reflect.has(object, property)
Reflect.has
is used to find if an object property exists or not. It’s same as the in
operator. The first argument is the object reference and second argument is the property name.
Here is an example to demonstrate the Reflect.has
method:
console.log(Reflect.has(obj, "name")); //Output "true"
Reflect.has()
is simply an alternate to in
operator and they both can be used alternatively.
Reflect.getOwnPropertyDescriptor(object, property)
Reflect.getOwnPropertyDescriptor
is used to retrieve descriptor of an object property. It’s same as the Object.getOwnPropertyDescriptor
method. The first parameter is the object reference and the second parameter is the property name.
Here is an example to demonstrate the Object.getOwnPropertyDescriptor
method:
var descriptor = Reflect.getOwnPropertyDescriptor(obj, "name");
console.log(descriptor);
Output is:
Reflect.ownKeys(object)
The
method returns an array whose values represent the keys of the properties of an provided object. It ignores the inherited properties. The only argument we need to pass is the object reference.
Here is an example to demonstrate Reflect.ownKeys
method:
var keys = Reflect.ownKeys(obj);
console.log(keys);
Output is:
Reflect.preventExtensions(object)
Reflect.preventExtensions
method is used to mark an object as non-extensible i.e., we cannot add new properties to it. It’s same as the Object.preventExtensions
method.
Here is an example to demonstrate Reflect.preventExtensions
method:
Reflect.preventExtensions(obj);
obj.name = "narayan";
console.log(obj.name); //Output "undefined"
Reflect.isExtensible(object)
Reflect.isExtensible
is used to check if an object is extensible or not. It same as the Object.isExtensible
method. It takes only one argument that is the object reference.
Here is an example to demonstrate the Reflect.isExtensible
method:
Reflect.preventExtensions(obj);
console.log(Reflect.isExtensible(obj)); //Output "false"
Reflect.setPrototypeOf(object, prototype)
Reflect.setPrototypeOf
is used to set [[prototype]]
of an object. The first argument is the object reference and second argument can be either null or an object.
Here is an example to demonstrate the Reflect.setPrototypeOf
method:
Reflect.setPrototypeOf(obj, {name: "narayan"});
console.log(obj.name); //Output "narayan"
Reflect.getPrototypeOf(object)
Reflect.getPrototypeOf
is used to retrieve the [[prototype]]
of an object. The only argument it takes is the object reference.
Here is an example to demonstrate the Reflect.getPrototypeOf
method:
Reflect.setPrototypeOf(obj, {name: "narayan"});
console.log(Reflect.getPrototypeOf(obj));
Output is:
Reflect.enumerate(object)
Reflect.enumerate
method takes an object as argument and returns an iterator object that contains the enumerable properties of the object. It also returns the enumerable inherited properties of an object.
Here is an example to demonstrate the Reflect.enumerate
method:
var iterator = Reflect.enumerate(obj);
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().done);
Output is:
profession
true
Reflect.apply(function[, this, args])
The
method is used to invoke a function with a given this
value. The first argument is the reference to the function object, second argument is the value of this
keyword and finally the third argument is an array whose values will be passed as arguments while invoking the function.
Here is an example to demonstrate the Reflect.apply
method:
{
return this + x + y;
}
var value = Reflect.apply(function_name, 30, [10, 20]);
console.log(value); //Output "60"
Reflect.construct(constructor[, args, prototype])
The Reflect.construct
method is used to invoke a function as a constructor. The first argument is the function reference, second argument is an array whose values will be passed as the argument to the constructor and finally the third argument is another constructor whose prototype
will be used as the prototype
of the currently invoked constructor.
Here is an example to demonstrate the Reflect.construct
method:
{
this.a = a;
this.b = b;
this.f = function(){
return this.a + this.b + this.c;
}
}
function constructor2(){}
constructor2.prototype.c = 30;
var obj = Reflect.construct(constructor1, [10, 20], constructor2);
console.log(obj.f()); //Output "60"
Why use the Reflect API?
Here are some of the reasons why we may want to use the Reflect API for object reflection:
In case we want to invoke a constructor with a prototype
of another constructor then we would usually copy the original prototype
property to a different variable and after invocation we would copy it back. But ES2015 makes it easy by providing the Reflect.constructor
method which takes a prototype
as its third argument. Here is an example to demonstrate this:
constructor1.prototype.print = function(){
console.log("Constructor 1");
}
function constructor2(){}
constructor2.prototype.print = function(){
console.log("Constructor 2");
}
//In ES5
var tmpPrototype = constructor1.prototype;
constructor1.prototype = constructor2.prototype;
var obj1 = new constructor1();
obj1.print();
constructor1.prototype = tmpPrototype;
//In ES5
obj1 = Reflect.construct(constructor1, [], constructor2);
obj1.print();
Another case where we would find Reflect API useful is while using Object.defineProperty
. It throws exception if it fails to do the operation but Reflect.defineProperty
don’t throw exception instead it returns false
which makes it easy to handle failure. Here is code example to demonstrate this:
var o = {};
Object.defineProperty(o, 'a', {
get: function() { return 1; },
configurable: false
});
try
{
Object.defineProperty(o, 'a', { configurable: true });
}
catch(e)
{
console.log("Exception");
}
//In ES2015
var o = {};
Reflect.defineProperty(o, 'a', {
get: function() { return 1; },
configurable: false
});
if(Reflect.defineProperty(o, 'a', { configurable: true }))
{
}
else
{
console.log("Operation Failed");
}
Similarly none of the methods of the Reflect API throw exception.
Conclusion
In this tutorial, we learned what the object reflection is, and how to use the ES2015 Reflect API for the object reflection. We saw various methods of the Reflect object with examples. Overall, this article introduced the ES2015 Reflect API to inspect and manipulate the properties of objects.