Overview
Each of the methods covered in this post is incredibly powerful, in that they allow us to write less code that does more.
This is especially true as we start to work with 'realistic' sets of data - usuallyarrays ofobject literals.
The 'Underling' Superpowers
These first 3 are somewhat useful for specific tasks. If we are going with this 🦸🏽♂️ analogy, these might be the 'apprentices,' - 'padawans,' if you will.
find
Usefind to..find and return the firstelement in anarray that meets some true/false condition.
consttodos=[{"id":1,"text":"Take out the trash","completed":false},{"id":2,"text":"Shop at Fresh Thyme","completed":false},{"id":3,"text":"Call Mom","completed":true},{"id":4,"text":"Mow lawn","completed":true},{"id":5,"text":"Litter Boxes Cleanup","completed":false,"assignee":"Mary"}]// Find the first 'completed' tasktodos.find(function(todo){returntodo.completed})We can rewrite using a 'one line'fat arrow:todos.find(todo => todo.completed)
The 🔑 to understanding this is thepredicate callback function: (todo => todo.completed).
Apredicate callback function is nothing but acallback thatreturns based on uponcoercion to eithertrue orfalse.
In other words:
- Iterate over
todos, passing in each 'todo' one at a time. - Have a look 👀 at
todo.completed. If it'strue,returnthistodo. If not, just move on.
find will stopiterating as soon as it finds the first 'match' It returns one single element from thatarray (if there is one that meets the _predicate condition)._
Refactor ♻️ with Destructuring
todos.find(({completed}) => completed) 🤓
some
Use this in a similar fashion tofind 👆🏽, but here we just get backtrue orfalse as long as at least oneelement in thearray meets the predicate condition.
So, given the same data set as above 👆🏽:todos.some(({completed} => completed)will just give us backtrue` because there at leastsome task has been completed ✅.
Likefind, this one stopsiterating once it finds a 'truthy'element.
every
Same assome but makes sure thatall theelements in thearray meet thepredicate. This one continues toiterate until it finds a 'fasle-y' element.
Again, given, that data set 👆🏽,todos.every(({completed} => completed) returnsfalse` b/c notevery task has been completed ✅.
The 'Main Roster' Superpowers
These next couple are used quite frequently - they are the 'workhorse' superpowers, getting a lot of things done.
Thesealways return a new array.
map
We use this to perform some type of 'transform' on each and every element.
Eachelement is passed into acallback function. Thefunction does something to eachelement, one at a time, creating a newarray along the way.
Let's start by 'mapping' over a simplearray ofnumbers, 'transforming' each one by doubling it. This example is taken fromMDN.
constarray1=[1,4,9,16];// pass a function to mapconstmap1=array1.map(x=>x*2);console.log(map1);// expected output: Array [2, 8, 18, 32]array1 andmap1 are totally separatearrays.array1 has not beenmutated at all! 👏🏽
Now, let's do one with thetodos data from above 👆🏽. This time we'll 'complete' all of the tasks:
todos.map(todo=>{todo.completed=true;returntodo;})This will create a new array with all of theelements having:completed: true.
However, if we check the originaltodos, we will see that all of those 'todos' have been 'completed' also! 👎🏽
This is due to how JS treatsobjects. Essentially, thereferences in memory 🧠 are shared.
Going into the particulars of 'copy/value vs reference' is a topic for another day, but since React relies heavily on 'no mutations,' let's at least see the code to fix this. We'll use theobject spread operator to create a 'fresh reference' to a totally newobject before updatingcompleted to betrue.
todos.map(todo=>{constcurrentTodo={...todo}currentTodo.completed=true;returncurrentTodo;})In case you need more info on...:
Now, the originalarray and all of the objects therein arenotmutated, and we have a newarray with the 'completed' data. 🤓
⚠️ You may be tempted to tryobject destructuring withmap. This is usually not desirable as once you perform thedestructuring, you are limited to returning only those 🔑s that youdestructured.
For example 🙅🏽♂️:
todos.map(({completed})=>{completed=true;returncompleted;})would give us back:[ true, true, true, true, true ]. So, generally, stay away fromobject destructuring when mapping.
Another common mistake is if you forget to explicitly return something from your 'map callback.' This will result in your 'mapped array' being full ofundefined.
todos.map(todo=>{constcurrentTodo={...todo}currentTodo.completed=true;// No return? Returning undefined!})filter
This one works almost the same asfind in that it uses apredicate callback function. However, rather than just returning a single element,filter willtraverse the entirearray, continuing to 'filter' 'truth-y'elements into a 'fresh new array.'
Let's filter out all of the even numbers (numbers that are divisible by 2 with no remainder) from anarray ofnumbers:
constnums=[1,4,9,16]constevens=nums.filter(num=>!(num%2))Again, we rely on apredicate callback function:num => !(num % 2)
- We pass in each 'num'
- Is
num % 2'false-y'? (i.e. Is the remainder 0?) - Add theunary inverse operator:
!to make it 'truthy' so that itreturns to our 'filtered array.'
Again,filterreturns theelement to a newarrayif thecallback functionreturnstrue.
In this scenario, we ask, "Is it true that when we divide this number by 2 that the remainder is 'false-y'/0?"
Now, let's modify what we did forfind earlier andfilter our 'completed' tasks:todos.filter(({completed} => completed).
Just with one line of code, we have completed our task. We have all of the original data intodos, and we have a separate 'filtered array' with just the 'completed' tasks. 👏🏽
map -filter ⛓️
These 'superpowers' can join forces. This time://TODO: Filter out all 'incomplete' tasks and then assign those to 'Mary.'
Once again, using:todos above 👆🏽:
todos.filter(({completed})=>// Return if it's NOT completed!completed).// Continue the chain by mapping over the 'incomplete tasks'map(todo=>{constcurrentTodo={...todo};currentTodo.assignee="Mary";returncurrentTodo;})The results:
[{id:1,text:'Take out the trash',completed:false,assignee:'Mary'},{id:2,text:'Shop at Fresh Thyme',completed:false,assignee:'Mary'},{id:5,text:'Litter Boxes Cleanup',completed:false,assignee:'Mary'}]The 'Leader' 👑 of the Array Superpowers 🦸🏽♂️
One reason whyreduce is the most powerful of all of these is b/c,technically it can do the job of any of the 👆🏽. That being said, use the right tool for the right job - just b/c youcan (and it's quite challenging, actually), doesn't mean that you should.
Usereduce to...reduce yourarray into one single 'accumulated thing.'
One of the differences is that thereducecallback functionrequires twoparameters:
- An 'accumulator' to keep track of the '🏃🏽♂️ total.'
- A 'current element' to keep track of...the current element in thearray as wetraverse.
For simplicity, we start with the most basic example, summing up numbers in anarray:
constnums=[1,2,3,4];consttotal=nums.reduce((// 'total' is initialized with the value of the first element -'1'total,// 'num' initializes as the 2nd element's value - '2'num)=>{// Add 'total' tototal+=num;returntotal;})There is a lot more toreduce that we can do. This example just scratches the surface. In the next post, we'll do some more 'practical'/intermediate things withmap,filter andreduce.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse




