Enumerable in Javascript is basically an ability of a particular property of an object to exist and visible at the same time. Very subtle, what does that it even? Let's dive a bit more.
While I was going through the official spec of EcmaScript to understand how the Polyfills should be written and have been written so far according to standards, I came across this word called, 'Enumerable' many times and I would be lying if I say that I understood everything in the first glance. This word itself was so confusing for me, so I did some more research about this and will share my findings, understanding so far that further made me understand other concepts better.
Objects in JavaScript
JavaScript is full of objects and every object has a key-value pair otherwise it's just an empty object. I'll be using the below-mentioned code snippet throughout the article to discuss.
var obj = {
first_name: 'Prateek',
last_name: 'Gogia',
profession: 'Code Gambler',
age: 25,
location: 'Internet',
known_as: 'reeversedev',
prints_name: function() {
console.log("My name is: " + this.first_name + " " + this.last_name)
}
};
There are various methods associated with objects. For example, Object.keys(obj) and Object.values(obj) will return array of keys and values by iterating over every key and value. The below snippet explains what will be returned while we use these methods.
console.log(Object.keys(obj)); // ["first_name", "last_name", "profession", "age", "location", "known_as", "prints_name"]
console.log(Object.values(obj)); // ["Prateek", "Gogia", "Code Gambler", 25, "Internet", "reeversedev", ƒ]
Every object in JavaScript has three attributes for its properties, writability, enumerability, and configurability. We are going to talk about Enumerability here.
What the heck is Enumerability?
In simple words, Enumerability allows your object to have properties to exist in the object but it provides a provision to be and not be a part of the iteration. Let's say my object has to be used by some other library that provides the functionality of printing name just like my object but with extra features, at the same time, I don't want the other developer whoever is using my object to change the prints_name() function to change. Any idea how can we do that? Yes, Enumeration is the answer. Let's see how we can do this for our object.
Object.defineProperty(obj, 'prints_name', {
value: function() {
console.log("My name is: " + this.first_name + " " + this.last_name)
},
enumerable: false
});
// Notice that, prints_name is not printed in console.
console.log(Object.keys(obj)); // ["first_name", "last_name", "profession", "age", "location", "known_as"]
// But you can still access the proper
console.log(obj.prints_name()); // My name is: Prateek Gogia
By default, the inbuilt properties of Objects are non-enumerable i.e., they won't be a part of the iteration, this becomes very important while you are dealing with bigger objects that include information and some methods/factory functions because while iterating, you all need access to information and not the utilities.
Utility functions of Array-like .pop() and .push() are non-enumerable and therefore you can access these properties but when you will console the whole array they won't be visible. To understand better, let's take a look at the example below.
// declaring the array
var arr = [1, 2, 3];
// expected behaviour
console.log(arr); // [1, 2, 3]
// Notice that JS won't throw an error when you use array as an Object, thanks to protype chain in JS
console.log(Object.keys(arr)); // ["0", "1", "2"]
console.log(arr.hasOwnProperty('push')) // false
In the above example, notice that when we check for our declared array, i.e., arr has a property such as 'push' or not, it return false. But you can still write arr.push(4)
and it will work. This means, that the utility function of the Array class has push and pop but they are non-enumerable and will not appear in iteration.
When do we need Enumeration though?
Usually, enumeration is being used when a developer tries to write polyfills of some functionality that doesn't work in incompatible browsers. As a result, he/she will try to modify the prototype object that makes the property enumerable and hence makes it risky because it will be returned in the iteration process.
So, instead of writing
Object.prototype.prints_name = function () {
alert("The name is bond, James Bond");
};
Using, Object.defineProperty
by defining enumerable
as false
makes more sense.
Object.defineProperty(Object.prototype, 'prints_name', {
value: function () {
alert("The name is bond, James Bond");
},
enumerable: false
});