Categories
JavaScript JavaScript Basics

Why it’s time to ditch the for…in Loop in JavaScript?

Spread the love

Since ES5.1, we have new features for iterating through the properties of an object. In the past, we only had the for...in loop to accomplish this.

In this article, we’ll look at why the new ways to loop through the properties of an object are much better than the for...in loop. This includes the Object.keys method, which is available since ES5.1, but updated in ES6 to support Symbols, and the Object.entries and Object.values methods new to ES2017. To loop through Symbol keys, we have the Reflect.ownKeys method.

Characteristics of the for…in Loop

The for...in loop lets us iterate over the non-Symbol, enumerable properties of an object.

It will iterate over the properties of an object in arbitrary order. Therefore, we can’t depend on the order of which the keys of an object are iterated over.

The properties that are deleted with the delete keyword won’t be iterated over. If a property is modified during iteration, then the value when it’s visited later will be the value after the change is done.

Modifying an object’s properties during iteration is a bad idea since it creates confusion because of the characteristics mentioned above.

Some people also use it for iterating through arrays since the for...in will get the indexes of an array like the keys of an object. However, this is again a bad idea since the order isn’t guaranteed.

Also, it iterates over its own properties and its prototype’s properties. For example, if we have:

const person = {  
  name: 'Joe'  
};  
const employee = {  
  title: 'waiter'  
};

employee.__proto__ = person;  
for (let prop in employee) {  
  console.log(prop);}

Then we see both name and title logged from the console.log in the for...in loop.

We might not want this, so we have to use the hasOwnProperty method from an object’s prototype to check if the property is actually an object’s own property as follows:

const person = {  
  name: 'Joe'  
};  
const employee = {  
  title: 'waiter'  
};

employee.__proto__ = person;  
for (let prop in employee) {  
  if (employee.hasOwnProperty(prop)) {  
    console.log(prop);  
  }  
}

As we can see, without hasOwnProperty, the for...in loop loops through all the own and inherited properties of an object.

This isn’t very convenient since it’s often not what we want.

Also, since the for...in loop was introduced before ES6 and was never updated, it’s not aware of Symbol property keys, so if we have the following object:

const foo = {  
  [Symbol('foo')]: 'Joe'  
};

When we try to loop through the foo object as follows:

for (let prop in foo) {  
  console.log(prop);  
}

We get nothing.

for…in Loop’s Performance

The for...in loop is also slow. This is because the loop has to check if each property is enumerable all the way up the prototype chain and then return the name of each enumerable property.

Getting it to work with arbitrary objects is tough because the structure isn’t constant. It has to check each key and its prototype’s keys to do this for each property. Therefore, a lot more computation is involved than a simple for loop.

Of course, the bigger the array or object, the bigger this issue is, but this is still something to keep in mind for those situations.

New Ways to Iterate Through Properties of an Object

Object.keys

Since ES5.1, we have the Object.keys method to get the keys of an object and return them as an array.

The keys are returned in the following order. First are keys with integer indexes in ascending numeric order. Then all other string keys in the order which they’re added to the object.

Unlike the for...in loop, there’s some reasoning to the order in which the keys are returned. And since Object.keys returns an array, we can sort it however we like.

We can also use the for...of loop or forEach method to write a cleaner loop.

Also, we don’t have to use hasOwnProperty to check if an object’s properties are its own properties anymore.

Since Object.keys is released with ES6, Symbols are supported.

For example, given that we have the same inherited object as the above example:

const person = {  
  name: 'Joe'  
};  
const employee = {  
  title: 'waiter'  
};

employee.__proto__ = person;

We can loop through it as follows:

for (let prop of Object.keys(employee)) {  
  console.log(prop);  
}

We only get back 'title' from the loop above.

The ordering can be seen as follows. If we have the following object:

const foo = {  
  a: 1,  
  b: 2,  
  1: 'a',  
  2: 'b',  
  3: 'c',  
};

When we loop through the keys with:

for (let prop of Object.keys(foo)) {  
  console.log(prop);  
}

Then we get back:

1  
2  
3  
a  
b

Object.values

To get the values from an object’s without the inherited properties, we can use the Object.values() method.

The order of iteration is the same as Object.keys , but we get back the values instead of the keys.

For example, given the following objects:

const person = {  
  name: 'Joe'  
};  
const employee = {  
  title: 'waiter'  
};  
employee.__proto__ = person;

We can loop through the own values of employee without the person ‘s property values as follows:

for (let val of Object.values(employee)) {  
  console.log(val);  
}

We should only get 'waiter' from the console.log .

The Object.values method is new to ES2017.

Object.entries

To get the key-value pair in one loop, we can use the Object.entries method. It takes an object as an argument like the other methods we mentioned above.

The method returns an array that has the key-value pair of its own properties in an array.

For example, given that we have the following object:

const person = {  
  name: 'Joe'  
};  
const employee = {  
  title: 'waiter'  
};  
employee.__proto__ = person;

We can use the Object.entries method as follows:

for (let entry of Object.entries(employee)) {  
  console.log(entry);  
}

Then we get back:

["title", "waiter"]

That is the key and the value of the property in the employee respectively.

Reflect.ownKeys

None of the Object methods support Symbols. To loop through objects with Symbol keys, we can use the Reflect.ownKeys method. Like Object.keys , it gets the keys of an object’s own properties, but Symbol keys are also supported. And it also returns an array of keys. String keys are also supported like Object.keys.

For example, given that we have the following object:

const foo = {  
  [Symbol('foo')]: 'Joe'  
};

We can use Reflect.ownKeys:

for (let prop of Reflect.ownKeys(foo)) {  
  console.log(prop);  
}

Then we get back Symbol(foo) .

Getting values from Symbol keys also work if we write the following loop:

for (let prop of Reflect.ownKeys(foo)) {  
  console.log(foo[prop]);  
}

Then we get back 'Joe’ .

This method is new with ES6.

As we can see, since ES5.1 or later, we have many alternatives to using the for...in loop to loop through the properties of objects. The only feature that’s useful in the for...in loop is to loop through the inherited properties of an object.

Otherwise, we should use Object.keys , Object.entries , Object.values since they all return arrays of keys or values or both. Also, the order is predictable, unlike the for...in loop. Since arrays are returned, we can sort them and loop through the properties or values the way we like to.

If we need to loop through Symbol keys, we can use the Reflect.ownKeys method.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *