- 3.1 Declaring Functions
- 3.2 Higher-Order Functions
- 3.3 Function Literals
- 3.4 Arrow Functions
- 3.5 Functional Array Processing
- 3.6 Closures
- 3.7 Hard Objects
- 3.8 Strict Mode
- 3.9 Testing Argument Types
- 3.10 Supplying More or Fewer Arguments
- 3.11 Default Arguments
- 3.12 Rest Parameters and the Spread Operator
- 3.13 Simulating Named Arguments with Destructuring
- 3.14 Hoisting
- 3.15 Throwing Exceptions
- 3.16 Catching Exceptions
- 3.17 The finally Clause
- Exercises
3.5 Functional Array Processing
Instead of iterating over an array with a for of or for in loop, you can use the forEach method. Pass a function that processes the elements and index values:
arr.forEach((element, index) => { console.log(`${index}: ${element}`) })
The function is called for each array element, in increasing index order.
If you only care about the elements, you can pass a function with one parameter:
arr.forEach(element => { console.log(`${element}`) })
The forEach method will call this function with both the element and the index, but in this example, the index is ignored.
The forEach method doesn’t produce a result. Instead, the function that you pass to it must have some side effect—printing a value or making an assignment. It is even better if you can avoid side effects altogether and use methods such as map and filter that transform arrays into their desired form.
In Section 3.2, “Higher-Order Functions” (page 53), you saw the map method that transforms an array, applying a function to each element. Here is a practical example. Suppose you want to build an HTML list of items in an array. You can first enclose each of the items in a li element:
const enclose = (tag, contents) => `<${tag}>${contents}</${tag}>` const listItems = items.map(i => enclose('li', i))
Actually, it is safer to first escape & and < characters in the items. Let’s suppose we have an htmlEscape function for this purpose. (You will find an implementation in the book’s companion code.) Then we can first transform the items to make them safe, and then enclose them:
const listItems = items .map(htmlEscape) .map(i => enclose('li', i))
Now the result is an array of li elements. Next, we concatenate all strings with the Array.join method (see Chapter 7), and enclose the resulting string in a ul element:
const list = enclose('ul', items .map(htmlEscape) .map(i => enclose('li', i)) .join(''))
Another useful array method is filter. It receives a predicate function—a function that returns a Boolean (or Boolish) value. The result is an array of all elements that fulfill the predicate. Continuing the preceding example, we don’t want to include empty strings in the list. We can remove them like this:
const list = enclose('ul', items .filter(i => i.trim() !== '') .map(htmlEscape) .map(i => enclose('li', i)) .join(''))
This processing pipeline is a good example of a high-level “what, not how” style of programming. What do we want? Throw away empty strings, escape HTML, enclose items in li elements, and join them. How is this done? Ultimately, by a sequence of loops and branches, but that is an implementation detail.