Array iteration methods summarized
While attempting to explain JavaScript's reduce method on arrays, conceptually, I came up with the following - hopefully it's helpful; happy to tweak it if anyone has suggestions.
JavaScript Arrays have lots of built in methods on their prototype. Some of them mutate - ie, they change the underlying array in-place. Luckily, most of them do not - they instead return an entirely distinct array. Since arrays are conceptually a contiguous list of items, it helps code clarity and maintainability a lot to be able to operate on them in a "functional" way. (I'll also insist on referring to an array as a "list" - although in some languages, List is a native data type, in JS and this post, I'm referring to the concept. Everywhere I use the word "list" you can assume I'm talking about a JS Array) This means, to perform a single operation on the list as a whole ("atomically"), and to return a new list - thus making it much simpler to think about both the old list and the new one, what they contain, and what happened during the operation.
Below are some of the methods that iterate - in other words, that operate on the entire list, one item at a time. When you call them, you provide a callback function - a single function that expects to operate on one item at a time. Based on the Array method you've chosen, the callback gets specific arguments, and may be expected to return a certain kind of value - and (except for forEach) the return value determines the final return value of the overarching array operation. Although most of the methods are guaranteed to execute for each item in the array - for all of them - some of the methods can stop iterating partway through; when applicable, this is indicated below.
All array methods iterate in what is traditionally called "left to right" - more accurately (and less ethnocentrically) from index 0, to index length - 1 - also called "start" to "end". reduceRight is an exception in that it iterates in reverse - from end to start.
forEach:
item, index, listundefined[1, 2, 3].forEach(function (item, index) {
console.log(item, index);
});
map:
item, index, listconst three = [1, 2, 3];
const doubled = three.map(function (item) {
return item * 2;
});
console.log(three === doubled, doubled); // false, [2, 4, 6]
filter:
item, index, listconst ints = [1, 2, 3];
const evens = ints.filter(function (item) {
return item % 2 === 0;
});
console.log(ints === evens, evens); // false, [2]
reduce:
result, item, index, list// NOTE: `reduce` and `reduceRight` take an optional "initialValue" argument, after the reducer callback.
// if omitted, it will default to the first item.
const sum = [1, 2, 3].reduce(function (result, item) {
return result + item;
}, 0); // if the `0` is omitted, `1` will be the first `result`, and `2` will be the first `item`
reduceRight: (same as reduce, but in reversed order: last-to-first)
some:
item, index, listtrue after the first item that meets your criteria, else falseconst hasNegativeNumbers = [1, 2, 3, -1, 4].some(function (item) {
return item < 0;
});
console.log(hasNegativeNumbers); // true
every:
item, index, listfalse after the first item that failed to meet your criteria, else trueconst allPositiveNumbers = [1, 2, 3].every(function (item) {
return item > 0;
});
console.log(allPositiveNumbers); // true
find:
item, index, listconst objects = [{ id: 'a' }, { id: 'b' }, { id: 'c' }];
const found = objects.find(function (item) {
return item.id === 'b';
});
console.log(found === objects[1]); // true
findIndex:
item, index, list-1const objects = [{ id: 'a' }, { id: 'b' }, { id: 'c' }];
const foundIndex = objects.findIndex(function (item) {
return item.id === 'b';
});
console.log(foundIndex === 1); // true