When to reach for different JS methods while manipulating data
Array -> Array; structure different, length same
Reach for .map
Array -> Array; structure same, length different
Reach for .filter
Array -> Non-Array (like Object)
Reach for .reduce - easily one of the most powerful and flexible Array methods.
Object -> Object; structure different, length same
The “entries” are super helpful, given an object like this:
const data = {
  firstName: 'Evan',
  lastName: 'Lovely',
}
The “entries” (what you get if ran Object.entries(data)) would be:
[
  ['firstName', 'Evan'],
  ['lastName', 'Lovely'],
]
Being able to go to with Object.entries and from with Object.fromEntries is very powerful and you then can use all the Array methods to do manipulations - so in the case of structure different, length same you’d reach for .map:
Object.fromEntries(
  Object.entries(myObject).map(([key, value]) => {
    // manipulate
    return [key, value];
  }),
);
Array -> Array; different structure, different length
It’s common to chain .filter and .map together which works great if you are wanting a smaller number of items than you started with, but if you want to have the list grow - you’ll need to reach for something more powerful: .flatMap.
The common use of .flatMap is to use .map and then if you end up with an array of arrays to .flat them - however it can be much more powerful than that, from the MDN docs page:
For adding and removing items during a map()
flatMapcan be used as a way to add and remove items (modify the number of items) during amap. In other words, it allows you to map many items to many items (by handling each input item separately), rather than always one-to-one. In this sense, it works like the opposite offilter. Return a 1-element array to keep the item, a multiple-element array to add items, or a 0-element array to remove the item.