Welcome to "JavaScript: Tricks and tips" In this series of blogs, I'll show you some development tips and will solve some of the problems that I've faced during my career as a Software engineer.
Writing the Immutable JavaScript code is getting more popular every day. If you just google immutable javaScript, there are dozen of libraries and articles around it. But what is immutable?
Immutability
In short, an Immutable object cannot be changed once created. Let me give you an example: Let’s say we have an array of users and we want to add a new user to it: here is the mutable way of doing it:
let users = ['David', 'frank'];
users.push('John');
console.log(users.toString());
It works, but we broke the immutability rule, we changed our User array. Let’s fix it:
const users = ['David', 'frank'];
const newUsers = [...users, 'John'];
console.log(users.toString());
console.log(newUsers.toString());
Perfect. Now we have both original users array and newUsers array. You may ask, both approaches are working and produce the same result! Why should I bother myself? The answer is Immutability make programming safer by means, you do not modify the current state of the application by that, you have a single source of truth. In our first example, after you add john to the array and let's say you want to compare the old list to the new list, you may find it hard. But with the second approach, it’s easier since you have both arrays. Let’s do another example: Imagine we have a list of grades and we want to find the average. Simple right?
const grades = [90, 86, 40, 82];
let total = 0;
for (let i of grades){
total += i;
}
const average = total / grades.length;
console.log(average);
Let’s do it immutable way:
const grades = [90, 86, 40, 82];
const average = grades.reduce((pre, curr) => {
return pre + curr;
}) / grades.length;
console.log(average);
As you can see, the immutable approach is way cleaner and easier to read. This is another reason why I like to write immutable code.
Now, I like to introduce you to one of the most useful javaScript methods.
Filter
The filter method runs all of the array elements against a function that you provide and if they pass the criteria, it will create a new array and store that element. Because it does not modify the original array it is considered immutable. Let’s revisit our grade example and let’s say we want to print all the grades less than 85;
const grades = [90, 86, 40, 82];
const filtered = grades.filter(n => n < 85);
console.log(filtered);
It is really amazing how easy and powerful this method is. In general, immutability can lead to more readable code. Let’s do another example. This time we want to solve the famous problem of “You have an array of numbers, find even numbers and print them”. Let’s use the filter method and solve that problem:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function isEven(number) {
return (number % 2 === 0);
}
const evenNumbers = numbers.filter(isEven);
console.log(evenNumbers.toString());
For every member of numbers array, filter method calls isEven function and if the result comes back true, It adds it into the evenNumbers array.
Here comes the fun part! What if our isEven function is an async. Let’s try it.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function isEven(number) {
return new Promise((resolve)=>{
resolve((number % 2 === 0));
})
}
const evenNumbers = numbers.filter(isEven);
console.log(evenNumbers.toString());
When you run the code, the result would be “1, 2, 3, 4, 5, 6, 7, 8, 9”. Interesting! Our isEven function no longer works. The reason is “filter” does not support async functions (at least now). That gets us to another very popular method.
Map
“Map” is another popular native javaScript method. Its behavior is very similar to “Filter”, But the difference is it runs all of the array elements against a function that you provide and it will create a new array and store all the results. Let’s do it in action:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function isEven (number) {
return {isEven: number % 2 === 0, entry: number}
}
const evenOdd = numbers.map(isEven);
console.log(evenOdd);
The “Map” method calls isEven function for every array element in numbers array and isEven function returns a JSON representation of if the number is even and the number itself.
Now we know how the Map method is working, let’s put that in use and try to fix our async filter problem:
(async function () {
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function isEven(number) {
return new Promise((resolve) => {
resolve({isEven: number % 2 === 0, entry: number})
})
}
const result = (await Promise.all(numbers.map(isEven)))
.filter(n => n.isEven);
console.log(result);
})()
I know there is a lot happening here. It can be overwhelming. So let’s see what’s happening here.
I wrapped the whole execution around-invoking function. The reason I wrapped my code around that is I wanted to use async, wait type of promise. You can read more on this subject on https://javascript.info/async-await. Then I’m using Map to call isEven function. isEven function returns a promise so I add each and every promise into “Promise.all” method. “Promise.all” method takes an array of Promises and returns a single promise to fulfill and when all promises resolve, it returns an array of results which a JSON looks like this: [{isEven: true, entry: 2}, {isEven: false, entry: 3}]. Then I use the filter method to filter out all odd numbers.
Conclusion
We talked about Immutability and why it is important. We also talked about the filter method and discussed how we can use it to write immutable code. We talked about why we cannot use filter against an async function. Then we covered the map method and finally, we solved the mystery of how to filter an array with a function that returns a Promise.
Next, I'll do a two-part series on how to load-balance at the application layer.
Top comments (3)
Thanks for your feedback, My intention was to show my audience that the filter method is not working with an async function if you read the whole article and I was trying to show them a workaround. I'll take your feedback and update my article.
Thanks for the article, how bout for a next article explain the usage of Object.freeze, const etc?
Thanks Chris, Sure I'll write one.