Programming without For loops

You should use iterator methods for clarity and fewer side effects.

When I code I avoid using "for" loops for several reasons.

  • It is extremely easy to have "off by 1 error", especially when filtering an array.
  • Iteration variable just adds more noise to the scope
  • Most importantly, one has to read through the iteration code to understand what it does.

I prefer built-in Array or utility library iterators, like lodash or Ramda. Not only the code is shorter and has fewer variables, it expresses the intent a lot clearer. One can almost read the iteration as plain English sentence in most cases

1
2
3
var doubled = numbers.map(double);
var longNames = names.filter(minLength);
var totalAge = people.reduce(...);

There are only 3 cases when doing the iteration

  1. New array is created by transforming each value (.map)
  2. New array is created from items that pass the callback (.filter)
  3. Single value is computed from the array (.reduce, .some, .every)

In each case, one can understand the data flow much faster by looking at the iteration method, rather than looking from for (var k = ; ...) { ... } code.

Banning for loops

One can easily ban for(...) statements in the existing application using my custom rule no-for-loop for eslint. The rule is available with a few of my rules in bahmutov/eslint-rules. Just include the rules folder and set no-for-loops:2 in your eslint rules file.

Banning all for loops at once is surely to upset people. Thus I advice you to generate warning for the current code, but ban it for new or modified code. One can easily apply different eslint rules for old / new source files using aged Grunt plugin.

Finally, if you must allow a specific for() loop in your code, use /* eslint no-for-loops:0 */ right above the loop to allow only this specific instance.

Extra details

  • To prevent accidental original array modification inside .map for example, you should look into using immutable data structures, read Avoid side effects with immutable data structures.
  • You can easily iterate over objects, not just arrays. See Object iterators.
  • Array iterator methods are slower than for() loops, but you can optimize their performance, see Unorthodox Performance talk by Lodash's author.
  • If you need the iteration index (for example when merging two arrays), it is passed as second argument to the iteration
1
2
3
4
5
6
var people = names.map(function (name, k) {
return {
name: name,
age: ages[k]
};
});