You made it to the last post in the series, sorry it's delayed work priorities took precedence over writing this up. This time I will cover Array Helpers, now some of this were drafted into ES5.1 but finalised into code in ES6, so these have been known about for a little while before being public, and of course I am covering ES6 7 years after it was publicly released (always playing catchup in the dev world!).
Arrays are pretty much common place in any JS application, so it makes sense we have some common functions that we can call to help process/manipulate/handle them. ES6 introduced 6 new helper functions, namely:
- forEach
- map
- reduce
- filter
- find
- every
- and some
and in this article I am going to look into these into a bit more detail and we'll take a look at some examples along the way :)
## forEach()
The purpose of
forEach()
is a relatively simple, for each record in an array do something. So using our array, let's say we want to just output the objects into the DOM, we can use a function that does that, and use it as the parameter forforEach()
.forEach()
takes 2 parameters: -
function
, this is our processing function which itself can contain 3 parameters, these are:-
currentValue
(required) - this is the current element -
index
(optional) - this is the index of the current element -
arr
(optional) - this is the array that the current element exists in
-
-
thisValue
(optional) - This is a value to be passed into ourfunction
as it's reference tothis
Let's take a look at an example offorEach()
:
var blogs = [
{ id: 10, title: 'Daily JS' },
{ id: 20, title: 'Code Refactor Daily' },
{ id: 30, title: 'The Brightest React-ion' }
];
const outputBlogs = (blog) => {
document.body.innerHTML += `<p>${JSON.stringify(blog)}</p>`
};
blogs.forEach(outputBlogs)
This code will simply just output the following paragraph nodes at the end of the body element:
<p>{"id":10,"title":"Daily JS"}</p>
<p>{"id":20,"title":"Code Refactor Daily"}</p>
<p>{"id":30,"title":"The Brightest React-ion"}</p>
This is of course a very simple example, but very easily shows how we can walk through the array and perform a function on each entry. A more in-depth example would perhaps be an array of images, and we want to store the area these images would take up in another array. For example:
var images = [
{ height: 10, width: 30 },
{ height: 20, width: 90 },
{ height: 54, width: 32 }
];
var areas = [];
images.forEach(function(image){
areas.push(image.height * image.width)
})
document.body.innerHTML += `<p>${JSON.stringify(areas)}</p>`
In this example we would have the array printed out into a paragraph node that reads [300,1800,1728]
, so here what we have is a function that is being trigger on each array item, which takes 2 object properties, and then pushes them into another array which we then output.
map()
In the above example, we could have worked this differently, we could have instead used the map()
helper. Map essentially takes one array, iterates through it, processing it with another function, and appends the item to an array that map()
created. map()
takes 2 parameters:
-
function
, this is our map function which itself can contain 3 parameters, these are:-
currentValue
(required) - this is the current element -
index
(optional) - this is the index of the current element -
arr
(optional) - this is the array that the current element exists in
-
-
thisValue
(optional) - This is a value to be passed into ourfunction
as it's reference tothis
Let's take a look at an example:
var blogs = [
{ id: 10, title: 'Daily JS' },
{ id: 20, title: 'Code Refactor Daily' },
{ id: 30, title: 'The Brightest React-ion' }
];
let blogTitles = blogs.map((blog) => blog.title)
document.body.innerHTML += `<p>${JSON.stringify(blogTitles)}</p>`
In the above example we will have an output that reads: ["Daily JS","Code Refactor Daily","The Brightest React-ion"]
.
There is one thing to always ensure you remember with map()
and that is that you must ensure you return a value in your function else you will get an array of undefined values, the length will still be the same as the existing array but as your callback function doesn't return a value it cannot store anything.
As mentioned above the function you call inside of map()
can actually take 3 parameters, 2 of which are optional. We have already seen currentValue
which was blog
, we can also pass index
which is the index position of the current element, and arr
which outputs the array that contains the current element (I cannot find an actual useful implementation of this param, feel free to shout out with any example you might have found though). Let's take a look at our example above with the index added:
let blogTitles = blogs.map((blog, index) => `index: ${index} is ${blog.title}`)
document.body.innerHTML += `<p>${JSON.stringify(blogTitles)}</p>`
This updated example will now give us an output of ["index: 0 is Daily JS","index: 1 is Code Refactor Daily","index: 2 is The Brightest React-ion"]
. This functionality is a lot easy than using a traditional for loop where we would have to access something like i
for each element in the loop.
reduce()
The reduce()
filter is definitely an interesting filter, It will ingest the array elements, pass them through a "reducer function", and output an accumulated result. reduce()
takes 2 parameters:
-
function
, this is our reducer function which itself can contain 4 parameters, these are:-
total
(required) - this is the initialValue OR thw previously returned value of the function -
currentValue
(required) - this is the current element -
currentIndex
(optional) - this is the index of the current element -
arr
(optional) - this is the array that the current element exists in
-
-
initialValue
(optional) - This is a value to be passed into ourfunction
as it's initial value Let's look at an example:
var trips = [{ distance: 34 }, { distance: 12 } , { distance: 1 }];
var totalDistance = trips.reduce((sum, trip) => { return sum += trip.distance }, 0);
In our example above, we start our totalDistance
variable with an initialValue
of 0. Then we will traverse through our trips
array, and then for each item in there we call our reducer function, this takes sum
as the total
parameter (which defaults to 0 in our initialValue
), and trip
as the currentValue
. Our return from this function is our sum
/initialValue
+ the distance
property of the element we are currently on. If we run this in the browser is will tell us that totalDistance
is 47.
We would also use the reduce()
helper to aid us in counting the occurences of a string in an array. For example, let's say we have an inventory of IT equipment such as desks, we have a mix of sitting and standing style desks. Using the reduce()
function we can easily count these easily:
var desks = [
{ type: 'sitting' },
{ type: 'standing' },
{ type: 'sitting' },
{ type: 'sitting' },
{ type: 'standing' }
];
var deskTypes = desks.reduce(function(retVal, desk) {
retVal[desk.type] ++
return retVal
}, { sitting: 0, standing: 0 });
In the output above, we would see {sitting: 3, standing: 2}
, there is a slight shortfall in this example however if we wanted to count all the elements but they were not included in the initialValue
we could get such as {"sitting":3,"standing":1,"adjustable":null}
. There is a way to combat this, with the use to 2 seperate reducing functions, let's take a look:
function uniqueValues(array) {
var reducedToObject = array.reduce(function (retVal, desk) {
// If we have no retValue length,
// or if we cannot find desk element we add a new object property
if (
!retVal.length || !retVal.find(function (desks) {
return desks == desk.type;
})
) {
// Add the unique property to our object with a default 0 value
retVal[desk.type] = 0;
return retVal;
}
return retVal;
}, {});
return reducedToObject;
}
var desks = [
{ type: 'sitting' },
{ type: 'standing' },
{ type: 'sitting' },
{ type: 'sitting' },
{ type: 'standing' },
{ type: 'sitting' },
{ type: 'standing' },
{ type: 'adjustable' },
{ type: 'adjustable' },
];
var deskTypeCount = desks.reduce(function(retVal, desk) {
retVal[desk.type] ++
return retVal
}, uniqueValues(desks));
In the above example we will now use a reducer reducedToObject
to find the unique values in our array, we will then use that value in our deskTypeCount
reducer function, ultimately this gives us {"sitting":4,"standing":3,"adjustable":2}
. The reduce()
helper, is super powerful in scenarios just like this!
filter()
The filter()
handler quickly allows us to take one array, and output it to another array pulling a subset of entries from the first, if nothin in the original array matches the filter then we will get an empty array.
-
function
, this is our filter function which itself can contain 3 parameters, these are:-
currentValue
(required) - this is the current element -
index
(optional) - this is the index of the current element -
arr
(optional) - this is the array that the current element exists in
-
-
thisValue
(optional) - This is a value to be passed into ourfunction
as it's initial value Let's look at an example:
var blogs = [
{ id: 10, title: 'Daily JS' },
{ id: 20, title: 'Code Refactor Daily' },
{ id: 30, title: 'The Brightest React-ion' }
];
var filteredBlogs = blogs.filter(user => {
return blog.id > 10
})
In the above example filteredBlogs
will be the following array [{id: 20, title: "Code Refactor Daily"}, {id: 30, title: "The Brightest React-ion"}]
. We would also use filter utilise the index parameter for a subset of blog posts, perhaps for something like pagination and filtering. For example, lets say we want to filter for javascript blogs, and just look in a specific block of results. We could use date or similar, but to keep it simple we could do something like this just grouping in a range of index positions:
var blogs = [
{blogPostId:100, title:"The best JS Guide", category:"Javascript"},
{blogPostId:101, title:"Stefan's JS Guide", category:"Javascript"},
{blogPostId:102, title:"Stefan's Java Guide", category:"Java"},
{blogPostId:103, title:"Stefan's HTML Guide", category:"HTML"},
{blogPostId:104, title:"Stefan's NodeJS Guide", category:"Javascript"},
{blogPostId:105, title:"Phil's JS Guide", category:"Javascript"},
{blogPostId:106, title:"Phil's Java Guide", category:"Java"},
{blogPostId:107, title:"Phil's HTML Guide", category:"HTML"},
{blogPostId:108, title:"Phil's NodeJS Guide", category:"Javascript"},
{blogPostId:109, title:"Simon's JS Guide", category:"Javascript"},
{blogPostId:110, title:"Simon's Java Guide", category:"Java"},
{blogPostId:111, title:"Simon's HTML Guide", category:"HTML"},
{blogPostId:112, title:"Simon's NodeJS Guide", category:"Javascript"},
{blogPostId:113, title:"Charley's JS Guide", category:"Javascript"},
{blogPostId:114, title:"Charley's Java Guide", category:"Java"},
{blogPostId:115, title:"Charley's HTML Guide", category:"HTML"},
{blogPostId:116, title:"Charley's NodeJS Guide", category:"Javascript"},
]
const filteredBlogs = (blogPosts,page, category) => {
return blogPosts.filter((post,index) => {
return (index > (page-1) * 5 && index < page * 5 && post.category == category)
})
}
With the example above, if we were to call filteredBlogs(blogs,1,"Javascript")
we would get a result such as [{ blogPostId: 101, category: "Javascript", title: "Stefan's JS Guide"}, { blogPostId: 104, category: "Javascript", title: "Stefan's NodeJS Guide"}]
because we wanted posts between index position 0 and 5 with a category of "Javascript"
find()
The find()
helper is usefuly for finding the first element that passes a test. find()
takes 2 parameters:
-
function
, this is our finder function which itself can contain 3 parameters, these are:-
currentValue
(required) - this is the current element -
index
(optional) - this is the index of the current element -
arr
(optional) - this is the array that the current element exists in
-
-
thisValue
(optional) - This is a value to be passed into ourfunction
as it's reference tothis
An example we could use is using find to find the first blog in our Javascript category from our example above, for example:
var blogs = [
{blogPostId:100, title:"The best JS Guide", category:"Javascript"},
{blogPostId:101, title:"Stefan's JS Guide", category:"Javascript"},
{blogPostId:102, title:"Stefan's Java Guide", category:"Java"},
{blogPostId:103, title:"Stefan's HTML Guide", category:"HTML"},
{blogPostId:104, title:"Stefan's NodeJS Guide", category:"Javascript"},
{blogPostId:105, title:"Phil's JS Guide", category:"Javascript"},
{blogPostId:106, title:"Phil's Java Guide", category:"Java"},
{blogPostId:107, title:"Phil's HTML Guide", category:"HTML"},
{blogPostId:108, title:"Phil's NodeJS Guide", category:"Javascript"},
{blogPostId:109, title:"Simon's JS Guide", category:"Javascript"},
{blogPostId:110, title:"Simon's Java Guide", category:"Java"},
{blogPostId:111, title:"Simon's HTML Guide", category:"HTML"},
{blogPostId:112, title:"Simon's NodeJS Guide", category:"Javascript"},
{blogPostId:113, title:"Charley's JS Guide", category:"Javascript"},
{blogPostId:114, title:"Charley's Java Guide", category:"Java"},
{blogPostId:115, title:"Charley's HTML Guide", category:"HTML"},
{blogPostId:116, title:"Charley's NodeJS Guide", category:"Javascript"},
]
const findFirstJSBlog = blogs.find(blog => {return blog.category === "Javascript"})
In this example, we will see that findFirstJSBlog
gives the return value of {blogPostId: 100, category: "Javascript", title: "The best JS Guide"}
. If we wanted to find an element by index, we could run the following:
const findFirstJSBlog = blogs.find((blog, index) => {return index === 1})
This would then give us { blogPostId: 101, category: "Javascript", title: "Stefan's JS Guide"}
, a good use case here would be for a previous/next page button in a blog system, for example if your blogs array was for the blog posts, you could then do something like the following:
let currentBlogIndex = 1
const findBlogByIndex = (position) => {
switch (position) {
case 'prev':
currentBlogIndex -= -1
break;
case 'next':
currentBlogIndex += +1;
break;
}
return blogs.find((blog, index) => {
return index === currentBlogIndex
})
}
const findCurrentJSBlog = findBlogByIndex('current')
const findPrevJSBlog = findBlogByIndex('prev')
const findNextJSBlog = findBlogByIndex('next')
The above code allows us to easily get the current, previous, and next blog posts, with the 3 variables at the end giving us { blogPostId: 101, category: "Javascript", title: "Stefan's JS Guide"}
, { blogPostId: 100, category: "Javascript", title: "The best JS Guide"}
, and { blogPostId: 102, category: "Javascript", title: "Stefan's Java Guide"}
every() and some()
Finally, we hit the last 2 helpers, every()
and some()
are probably the most logical sounding helpers from the whole bunch. Simply put, they will check an array, and return a boolean value based on the conditions of either every element or some elements matching the function condition. You could use this for form validation to ensure all required fields are completed (if you aren't already relying on built in validation supplied by most browsers), maybe you want to check that a series of requests are completed, we'll keep our example simple however and let's look at an array of objects listing blog posts again:
var blogs = [
{blogPostId:100, title:"The best JS Guide", category:"Javascript", published: true},
{blogPostId:101, title:"Stefan's JS Guide", category:"Javascript", published: true},
{blogPostId:102, title:"Stefan's Java Guide", category:"Java", published: false},
{blogPostId:103, title:"Stefan's HTML Guide", category:"HTML", published: true}
]
const everyBlogPublished = blogs.every((blog) => {return blog.published})
const someBlogsPublished = blogs.some((blog) => {return blog.published})
If we were to call the two consts above, everyBlogPublished
would return false
and someBlogsPublished
would return true
. Pretty neat huh? There are literally tonnes of examples and use cases for these helpers around online, I think that the above should help anyone get started, let me know if there are any other examples you've seen that you like.
Top comments (0)