DEV Community

Walter Miani
Walter Miani

Posted on • Edited on

Javascript Array Methods. All you really need to know.

The idea of this post is to show you the minimum set of methods you need to deal with to get away with any array-related problems you might encounter on an average development day.
And when I say any problem I obviously mean the 99% of ’em…there will always be something absurd that the human mind has not yet learned to solve with simple ideas.

Who is this post for? This is for someone who is starting to get comfortable with javascript but isn’t a ninja yet. It is for those looking for a summary of what to know and use when working with arrays, to create a solid foundation from which to start your journey through becoming a javascriptmegaexpert.

Oh, if I talk bullshit let me know.


Table of contents

Level 1

push
forEach
map
filter

Level 2

includes
find
indexOf

Level 3

slice
findIndex
join
splice

Level 4

shift
sort
pop

Bonus

some / every
unshift
reduce

So, there are tons of array instance methods.

at, concat, copyWithin, entries, every, fill, filter, find, findIndex, flat, flatMap, foreach, includes, indexOf, join, keys, lastIndexOf, map, pop, push, reduce, reverse, shift, slice, some, sort, splice, toLocaleString, toString, unshift, values

and maybe I left out something.

But… what do you REALLY need to know to cover all your array necessities?

After 5+ years of experience with Javascript I’m gonna tell you which ones I use the most and show you some interesting use cases.
They’ll be divided into frequencies of use.

LEVEL 1 - used every 3 to 4 minutes

push

It just adds one or more values at the end of an array. Easy Peasy.

var array = []

array.push(1)
array.push(2,3,4)
array.push(...[5,6,7])

console.log(array) // [ 1, 2, 3, 4, 5, 6, 7 ]
Enter fullscreen mode Exit fullscreen mode

Just keep in mind that when you add more than one element you don’t have to pass an array of elements as the argument of the push method, but rather all the elements you want to add separately (which as you can see in the example before can be done with the ... operator)

If you pass an array, it will add an array in the array.

var array = []

array.push([1,2,3])

array.push(...[4,5,6])

console.log(array) // [ [ 1, 2, 3 ], 4, 5, 6 ]
console.log('array has ' + array.length + ' elements') // 'array has 4 elements'
Enter fullscreen mode Exit fullscreen mode

I don’t remember myself using push to add more than one value at the time to an array in the last months. Just remember that there is also this possibility.

forEach

Basically do something for every element of an array... you choose what.

var array = ['pizza', 'pasta', 'chicken', 'cake']

console.log('Menu')

array.forEach((el,index) => {
  console.log(index+1 + ' - ' + el.toUpperCase())
})

// output
/*
'Menu'
'1 - PIZZA'
'2 - PASTA'
'3 - CHICKEN'
'4 - CAKE'
*/
Enter fullscreen mode Exit fullscreen mode

It’s a loop function, so it processes every element of the array, in order, separately.

syntax: a callback that takes 2 parameters, the first is the current element, the second is the index of the element in the array (it can actually take also a third parameter, which is the whole array itself, but I’ve never ever used it)

It does not return anything, you just use it to do something for every element of the array.

I normally don’t use forEach to modify elements of the array, for that purpose I would use the next method…

map

same syntax as forEach, you’ll need a callback with 1 or 2 arguments. The difference is that map returns a new array of the exact dimension of the starting array (obviously)… the value of each new element is the return value of the callback.

var array = [1,2,3,4,5,6,7,8,9]

var out = array.map((el,i) => {  
  return el*2  
})

console.log(out) // [ 2, 4, 6, 8, 10, 12, 14, 16, 18 ]
Enter fullscreen mode Exit fullscreen mode

filter

Use filter when you have an array but at some point you need only some of its elements.
It returns a new array which elements are all the elements that passes the test you provide as callback, same old syntax.
Here, the ‘survivor’ elements are those that make the callback return TRUE.

var array = [{food: 'pizza', price: 11}, {food: 'chicken', price: 13}, {food: 'icecream', price: 3}, {food: 'soup', price: 7}]

var onlyCheapFood = array.filter(f => f.price < 10)

console.log(onlyCheapFood)

// [
//  { food: 'icecream', price: 3 },
//  { food: 'soup', price: 7 }
// ]
Enter fullscreen mode Exit fullscreen mode

A quite recurrent and useful application of filter is the following:
You have a table, and it needs an array of data as its input source. Along with the table comes a search input of some sort (either global or on one of the columns of the table) that allows you to filter the data (sorry, I had to use the word filter to explain what the method filter does).
So the table does not get the original array of data as input but a “filteredArray” based on the search input value.
If the search parameter are not set, the filteredArray is simply equivalent to the original array.

var data = [{product: 'trousers', price: 100}, 
           {product: 't-shirt', price: 15},
           {product: 'shoes', price: 55},
           {product: 'shirt', price: 80},
           {product: 'socks', price: 12},
           {product: 'hat', price: 22}]

const getDataForTable = (data, limit) => {
  return !limit? data: data.filter(d => d.price < limit)
}

var costLimit = 30


var filteredData1 = getDataForTable(data, costLimit)
var filteredData2 = getDataForTable(data)

console.log(filteredData1)
/*
[
  { product: 't-shirt', price: 15 },
  { product: 'socks', price: 12 },
  { product: 'hat', price: 22 }
] */

console.log(filteredData2)
/*
[
  { product: 'trousers', price: 100 },
  { product: 't-shirt', price: 15 },
  { product: 'shoes', price: 55 },
  { product: 'shirt', price: 80 },
  { product: 'socks', price: 12 },
  { product: 'hat', price: 22 }
] 
*/
Enter fullscreen mode Exit fullscreen mode

Beware: in case of arrays with great numbers of elements you probably better manage the filtering operation via backend (and maybe some sort of pagination), but we’re not gonna cover this in this post.

Beware part 2: in case of arrays of objects, filter does a shallow copy. So if then something changes in the original array, you'll find the edited value also in the new array.
You can avoid this by applying a map() to the filtered array. Here is an example.

var a = [{value: 1}, {value: 3}, {value: 1}]


var b = a.filter(o => o.value == 1)
var c = a.filter(o => o.value == 1).map(e => {return {...e}})

a[0].value = 2

console.log(b)

/*
[ { value: 2 }, { value: 1 } ]
*/

console.log(c)

/*
[ { value: 1 }, { value: 1 } ]
*/

Enter fullscreen mode Exit fullscreen mode

mixed examples

filter can be also used to thin out an array if you don’t need the original dataset, and can be concatenated multiple times in a row (like a pipeline).
Other methods like map can be added to the pipeline.
Here are some examples:


var func1 = a => a.length > 6
var func2 = a => a[0] == 'p'

var array = ['pizza', 'pepperoni', 'chicken', 'salami','pineapple', 'pasta', 'ice']

array = array.filter(func1).filter(func2)

console.log(array) // [ 'pepperoni', 'pineapple' ]
Enter fullscreen mode Exit fullscreen mode

var func1 = a=> a.length > 6
var func2 = a => a[0] == 'p'
var func3 = a => a.slice(-1)[0] == 'e'
var func4 = a => a.length < 15

var array = ['pizza', 'pepperoni', 'chicken', 'salami','pineapple', 'pasta', 'ice', 'pizza with a lot of cheese']

var filters = [func1,func2,func3,func4]

filters.forEach(f => {
  array = array.filter(f)
})

console.log(array) // [ 'pineapple' ]
Enter fullscreen mode Exit fullscreen mode
// take only even numbers and show their square

var array = [1,2,3,4,5,6,7,8,9,10]

var out = array.filter(n => n%2 == 0).map(n => n*n)

console.log(out) // [ 4, 16, 36, 64, 100 ]
Enter fullscreen mode Exit fullscreen mode

LEVEL 2 - used at least once every 5 hours

includes

It verifies if an array includes (no kidding!) an elements. It does not work with arrays of objects. You can also specify the start index as a second argument, never used that in my life though.

var hasFive = [1,2,3,4,5].includes(5)

console.log(hasFive) // true

var stuff = ['pasta', 'chicken', 'orange']
var hasPizza = stuff.includes('pizza')

console.log(hasPizza) // false
Enter fullscreen mode Exit fullscreen mode

This is VERY useful when more than one value is acceptable in some if statement.

// use includes:

if(['black','brown','navy blue','deep green'].includes(color)){
    console.log('it is dark!')
}

// instead of this:

if(color == 'black' || color == 'brown' || color == 'navy blue' || color == 'deep green') {
    console.log('it is dark!')
}
Enter fullscreen mode Exit fullscreen mode

find

Same syntax as filter, but it does not return a complete array, rather the first element of the array that passes the test. If no element passes the test, the return value is undefined


var lunchBaskets = [
  {food: 'pizza slices', quantity: 4}, 
  {food: 'pizza slices', quantity: 2},
  {food: 'sandwiches', quantity: 2},
  {food: 'donuts', quantity: 3}
]

var aLotOfPizza = lunchBaskets.find(b => b.food.includes('pizza') && b.quantity > 2)

console.log(aLotOfPizza) // { food: 'pizza slices', quantity: 4 }
Enter fullscreen mode Exit fullscreen mode

indexOf

In arrays of primitives (numbers, strings, booleans) indexOf returns the index of the searched value.
If there is more than one value that corresponds to the searched value, it will return the first index


var array = ['hatred', 'hatred', 'love', 'hatred', 'love']
var whereIsTheLove = array.indexOf('love')
console.log(whereIsTheLove) // 2
Enter fullscreen mode Exit fullscreen mode

Watch out! It does not work with arrays of objects.

var array = [{name: 'john'}, {name: 'peter'}]

var isTherePeter = array.indexOf({name: 'john'})

console.log(isTherePeter) // -1

// output is going to be ALWAYS -1, even if the array does have an object with 'john' value for the key 'name'
Enter fullscreen mode Exit fullscreen mode

LEVEL 3 - used on a weekly basis

slice

This method returns a subpart of an array, without modifying the array. It’s like substring for strings.
Very simple syntax.

var out = array.slice(A,B)

out array will have the elements of array from index A to index B-1.
You can even not pass the B index as an argument, slice will return all the elements from index A to the end of the array.

var array = [1,2,3,4,5,6,7]

console.log(array.slice(2,5)) // [ 3, 4, 5 ]
console.log(array.slice(2)) // [ 3, 4, 5, 6, 7 ]
Enter fullscreen mode Exit fullscreen mode

trick to take the last element

slice can also receive a negative number as argument (e.g array.slice(-3)).
In this case the output array will have the elements of the original array from index ‘array.lenght -1’ to the end of the array.
Let’s see an example to clarify this thing:

var array = [1,2,3,4,5,6,7]

console.log(array.slice(-3)) // [ 5, 6, 7 ]
Enter fullscreen mode Exit fullscreen mode

You can take advantage of this possibility to take the last element of an array without modifying the array.

var array = [1,2,3,4,5,6,7,8]

var lastElement = array.slice(-1)[0]

console.log(lastElement) // 8
Enter fullscreen mode Exit fullscreen mode

findIndex

This is very similar to indexOf, but you don’t provide an element, rather a callback. The return value of findIndex is the index of the first element that passes the test you pass as argument. Again, the same old syntax as filter, find and others.

var array = ['pizza', 'pasta', 'love', 'money']

var whereIsTheLove = array.indexOf('love')
var whereIsTheLove2 = array.findIndex(el => el == 'love')

console.log('Searched with indexOf: ' + whereIsTheLove) // 'Searched with indexOf: 2'
console.log('Searched with findIndex: ' + whereIsTheLove2) //  'Searched with findIndex: 2'
Enter fullscreen mode Exit fullscreen mode

As for find this is useful when you have an array of objects that cannot be analysed with a simple indexOf or includes.

var array = [{name: 'john'}, {name: 'wally'}, {name: 'peter'}]

var whereIsWally = array.findIndex(el => el.name == 'wally')

console.log('Wally is at index: ' + whereIsWally) // 'Wally is at index: 1'
Enter fullscreen mode Exit fullscreen mode

join

This is kinda different from the others because of its return value which is… a string.
It concatenates all the elements of an array in a single string putting a separator between the elements (no actually need to say that works better with arrays of strings) .
If nothing is specified the default separator is comma (‘,’).

var people = ['John', 'Francine', 'Wally', 'Peter', 'Anna']
var joined = people.join()
var joined2 = people.join(' and ')
console.log('Today there were ' + joined) // 'Today there were John,Francine,Wally,Peter,Anna'
console.log('Today there were ' + joined2) // 'Today there were John and Francine and Wally and Peter and Anna'
Enter fullscreen mode Exit fullscreen mode

If you want to join the strings without any separators just do as the following

var array = ['first','second','third']
var out = array.join('')
console.log(out) // firstsecondthird
Enter fullscreen mode Exit fullscreen mode

If you have an array of objects and you want to join one of the properties of the objects, you’re gonna need to use also a map before the join

var people = [{name: 'John'}, {name: 'Francine'}, {name: 'Peter'}, {name: 'Peter'}, {name: 'Anna'}]

var joined = people.map(el => el.name).join()

console.log('Today there were ' + joined) // 'Today there were John,Francine,Peter,Peter,Anna'
Enter fullscreen mode Exit fullscreen mode

Warning: If an element is undefined, null or an empty array [], it is converted to an empty string.

splice

Splice method is quite powerful. It allows you to remove elements from an array (permanently) and at the same time to add new elements.
Both operations are optional.
It returns an array containing the deleted elements.

Warning: it obviously modifies directly the array.

First, let’s analyse the syntax: splice(startIndex, deleteCount, item1, item2, … , itemN)

startIndex = where to start deleting and/or inserting
deleteCount = how many elements to delete starting from startIndex, can be 0.
Item1, … , itemN = the items to optionally insert.

Let’s see three basic examples that will certainly clarify how it works

// DELETE 2 ELEMENTS
var array1 = [1,2,3,4,5]
var out = array1.splice(1,2)
console.log(array1) // [ 1, 4, 5 ]
console.log(out) // [2,3]

// INSERT 2 ELEMENTS
var array2 = ['pizza', 'pasta', 'chicken']
array2.splice(2, 0, 'sandwich', 'cake')
console.log(array2) // [ 'pizza', 'pasta', 'sandwich', 'cake', 'chicken' ]

// REPLACE 1 ELEMENT WITH NEW STUFF
var array3 = [1,2,3,4,5]
array3.splice(2, 1, '*', '*', '*')
console.log(array3) // [ 1, 2, '*', '*', '*', 4, 5 ]
Enter fullscreen mode Exit fullscreen mode

And with these methods you are already well placed in almost all cases.

However, let’s see other methods that happen to be used less often, but with which you can start feeling like an almost-senior-developer and to be in the position of asking your boss for a promotion.

LEVEL 4 - used once every 2 months maybe?

shift

Takes off and returns the first element (index 0) of the array.
It’s pretty much equivalent to splice at index 0, but shift returns the element, not an array.
Shift is much faster than splice, but… you know, one more method to learn.

var array1 = [1,2,3,4]
var array2 = [1,2,3,4]

var out1 = array1.shift()
var out2 = array2.splice(0,1)

console.log(out1) // 1
console.log(out2) // [ 1 ]

console.log(array1) // [ 2, 3, 4 ]
console.log(array2) // [ 2, 3, 4 ]
Enter fullscreen mode Exit fullscreen mode

sort

It allows you to sort (again, no kidding!) the elements of an array. The problem is that it’s not intuitive at all. For basic sorting you’re gonna end up knowing by heart its syntax, for more complex cases you might wanna look up on the internet how to do it.

sort method seems like a big deal but you don’t really need to sort arrays a lot, a least in my experience. You normally put data into tables or charts (from third part libraries) and they all come with built-it sorting features or they automatically sort data for you. Or, data that should be sorted, come from some SQL or noSQL query, and you already put the sort direction in the query.

Anyway… the syntax is apparently simple:

array.sort()

This line of code sorts the elements of the array in alphabetical and ascending order (so the array is modified after sort is called).
It compares the sequences of UTF-16 code units values of the elements to make the sorting.

var array = ['blue', 'pizza','zebra', 'john', 'friends', 'anime']
array.sort()
console.log(array) // [ 'anime', 'blue', 'friends', 'john', 'pizza', 'zebra' ]
Enter fullscreen mode Exit fullscreen mode

WARNING: it is an alphabetical order, so you cannot use a simple sort() to order numbers.

var array = [1,3,7,211,5,4]
array.sort()
console.log(array) // [ 1, 211, 3, 4, 5, 7 ]
Enter fullscreen mode Exit fullscreen mode

BUT, you can specify a compare function as optional parameter, and it allows you to perform more complex sortings.

sort((a, b) => { /* ... */ } )

// Compare function
sort(compareFn)

// Inline compare function
sort(function compareFn(a, b) { /* ... */ })

Enter fullscreen mode Exit fullscreen mode

So the sorting is based on the compareFunction return value. In this function a and b represents two whatever elements of the array.
How does the compare function work? Something like this:

  • Return value is > 0: b goes before a
  • Return value is < 0: a goes before b
  • Return value is == 0: a and b take their original order

To explain this better let’s see two example.

The first is to order arrays of numbers, and this is the case you’re gonna end up using sort the 95% of the times:

var array = [1,3,7,211,5,4]

// ascending order
array.sort((a,b) => a-b) // [ 1, 3, 4, 5, 7, 211 ]
// descending order
array.sort((a,b) => b-a) // [ 211, 7, 5, 4, 3, 1 ]
Enter fullscreen mode Exit fullscreen mode

And a version with an array of objects

var array = [{name: 'john', score: 4}, {name: 'peter', score: 12}, {name: 'walter', score: 110}, {name: 'michael', score: 12}, {name: 'frank', score: 1}]

array.sort((a,b) => {
  if(a.score > b.score){
    return -1
  }
  if(a.score < b.score){
    return 1
  }
  if(a.score == b.score){
    return 0
  }
})

var whoIsTheBest = array.map(a => a.name)[0]

console.log(whoIsTheBest)
Enter fullscreen mode Exit fullscreen mode

I usually get the sorting direction wrong at the first try. Damn it!

pop

When applied to an array pop takes off the last element and returns it (it modifies the array).

If your objective is to just remove the last element It’s obviously equivalent to array.splice(array.length-1, 1)

It's very convenient when you have a string that represents a file path and you want to extract the file extension from it.

var path = '/some.tricky/path/to.some.file_1.txt'
var extension = path.split('.').pop()
console.log(extension) // 'txt'
Enter fullscreen mode Exit fullscreen mode

This can be achieved also using the slice(-1) trick. They are slightly different though because slice does not modify the array.


var array1 = [1,2,3,4,5]
var array2 = [1,2,3,4,5]

var out1 = array1.pop()
var out2 = array2.slice(-1)[0]

console.log('out1: ' + out1) // 5
console.log('out1: ' + out2) // 5

console.log(array1) // ['1,2,3,4']
console.log(array2) // [1,2,3,4,5']
Enter fullscreen mode Exit fullscreen mode

So it’s completely replaceable by splice/slice, but it’s a handy shortcut.


BONUS LEVEL: Nice to know methods which you can easily survive without, but hey they are so cool.

some / every

At least one / every element of the array passes the test you provide as callback. I put them here just because it happened to me to use them some days ago and I remembered they exist. Just in!

var pizzas = ['pizza', 'pizza', 'pizza', 'pizza']

var areTheyReallyAllPizzas = pizzas.every(p => p == 'pizza')

console.log(areTheyReallyAllPizzas) // true

var mixedFood = ['pasta', 'pizza', 'chicken', 'pizza']

var isThereAtLeastOnePizza = mixedFood.some(f => f == 'pizza')

console.log(isThereAtLeastOnePizza) // true
Enter fullscreen mode Exit fullscreen mode

same thing without some/every - be creative with what you know!

// EVERY
var pizzas = ['pizza', 'pizza', 'not pizza', 'pizza']

var areTheyReallyAllPizzas = true

pizzas.forEach(p => {
  if(p != 'pizza'){
    areTheyReallyAllPizzas = false
  }
})

console.log(areTheyReallyAllPizzas) // false

// OR

areTheyReallyAllPizzas = pizzas.filter(p => p !='pizza').length == 0
console.log(areTheyReallyAllPizzas) // false


// SOME
var mixedFood = ['pasta', 'pizza', 'chicken', 'pizza']
var areThereAtLeastOnePizza = mixedFood.filter(p => p == 'pizza').length > 0
console.log(areThereAtLeastOnePizza) // true
Enter fullscreen mode Exit fullscreen mode

unshift

It adds one or more elements (works exactly like push) at the beginning of the array.

With (not so) modern (anymore) javascript it can be easily replaced with the ... operator.
Since I guess that you’re gonna see three dots everywhere when you look for something on stack overflow in these days, I believe you’re never gonna use unshift.

var array1 = [1,2,3]
var array2 = [1,2,3]

array1.unshift(3,2,1,0)
console.log(array1) // [ 3, 2, 1, 0, 1, 2, 3 ]

array2 = [...[3,2,1,0], ...array2]
console.log(array2) // [ 3, 2, 1, 0, 1, 2, 3 ]
Enter fullscreen mode Exit fullscreen mode

reduce

reduce is very powerful, yet so little intuitive.
You want to use it when you need an output that depends on all the elements in an array in succession.
If you really cannot remember how to use reduce you can always use a for or forEach loop after having set an accumulation variabile outside the loop.

The callback takes 3 arguments: the first is the accumulator value (where the partial value in stored at every step), the second is the current element, the third is the index value (optional).

In the following example you see how to sum all the elements of a value but the element at index 0, starting with a value of 5.

var array = [1,2,3,4,5]

var out = array.reduce((acc,current,index) => {
  if(i != 0){
    return acc + current
  } else{
    return acc
  }
}, 5)

console.log(out) // 19
Enter fullscreen mode Exit fullscreen mode

reduceRight does the same thing starting from last index.

Listen to me, when you start learning array methods you don’t need reduce at all, yet it is so nice to show off your code and make other people think that you’re a Javascript Badass.

here it is an example on how to cope without reduce

// sum all the elements in an array starting from 3
var out = array.reduce((a,b) =>  a+b, 3)
Enter fullscreen mode Exit fullscreen mode
// Is equivalent to
var out2 = 3
array.forEach(e => out2+=e)
Enter fullscreen mode Exit fullscreen mode

Not that more complex, isn’t it?


And that’s pretty much it… I’m not saying that you don’t have to delve more deeply into the other methods or loops or ninja tricks, I’m just saying that in the past 5 years I used them just a very little number of times and I still have my job.

Top comments (13)

Collapse
 
mikedepetris profile image
Mike De Petris

ehm... the last part is in Italian ^_^

Collapse
 
walterego profile image
Walter Miani • Edited

Haha very nice. I must have published the wrong draft. Gonna correct it immediately.

Collapse
 
walterego profile image
Walter Miani

Done, thank you @mikedepetris . Pizza time now!

Collapse
 
mikedepetris profile image
Mike De Petris

"If find it very handy" --> "I find it very handy"
anyway pizza is always the answer.

Collapse
 
mikedepetris profile image
Mike De Petris

This is great and usefult writing Walter, thank you.

Collapse
 
rickdelpo1 profile image
Rick Delpo

Thanks for all the detail Walter. Was wondering if people use Lodash these days as a more intuitive way of understanding how reduce works. I had a use case for Lodash and wrote an AWS Lambda function with CRUD against an AWS S3 json file store.

Collapse
 
walterego profile image
Walter Miani

I use Lodash quite a lot, especially for the uniqBy and groupBy array methods. And also for its debounce and throttle. I actually wanted to write a paragraph for lodash in this post but in the end I decided against.

Collapse
 
rickdelpo1 profile image
Rick Delpo

Thanks, this is good to know because I do not write this kind of code too often. I still have trouble fully understanding the Reduce syntax because perhaps I am not that good at JS anyway. I am an SQL developer. Lodash seemed more user friendly.

Collapse
 
yaalfred profile image
Arturas-Alfredas Lapinskas

concat() method is missed

Collapse
 
walterego profile image
Walter Miani

concat is missing because I never use it. The point was to show what I personally use the most.

Collapse
 
walterego profile image
Walter Miani

I'd rather do as: var array3 = [...array1, ...array2] instead of using concat. I'm just more used to the '...' operator since it's also useful with objects.

Collapse
 
jonrandy profile image
Jon Randy 🎖️

reduce is the king of all of these. Super useful for many things

Collapse
 
walterego profile image
Walter Miani

It is very powerful... It isn't just that easy to bear in mind its syntax at the beginning... but when you get it, it's so cool put it in your code :)