Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Manav Misra
Manav Misra

Posted on

     

Array 'Superpowers' 🦸🏾

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})
Enter fullscreen modeExit fullscreen mode

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:

  1. Iterate overtodos, passing in each 'todo' one at a time.
  2. Have a look 👀 attodo.completed. If it'strue,return thistodo. 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]
Enter fullscreen modeExit fullscreen mode

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;})
Enter fullscreen modeExit fullscreen mode

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;})
Enter fullscreen modeExit fullscreen mode

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;})
Enter fullscreen modeExit fullscreen mode

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!})
Enter fullscreen modeExit fullscreen mode

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))
Enter fullscreen modeExit fullscreen mode

Again, we rely on apredicate callback function:num => !(num % 2)

  1. We pass in each 'num'
  2. Isnum % 2 'false-y'? (i.e. Is the remainder 0?)
  3. 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;})
Enter fullscreen modeExit fullscreen mode

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'}]
Enter fullscreen modeExit fullscreen mode

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:

  1. An 'accumulator' to keep track of the '🏃🏽‍♂️ total.'
  2. 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;})
Enter fullscreen modeExit fullscreen mode

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)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

I'm a JS Subject Matter Expert (SME) that has spent the past few years spearheading curricula and teaching initiatives at colleges and bootcamps, in person and virtually.
  • Location
    62236
  • Education
    BS - Mech. Eng. - Missouri S&T
  • Joined

More fromManav Misra

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp