Is performing a mapping operation without using returned value an antipattern?
Yes, this is an anti-pattern. Although you could argue it is not and it is just plain misuse. I would call it an anti-pattern because for some reason there is a frequent widespread incidents of people using .map()
when they should not.
The term comes from mathematics where you can map from one category to another. For example, shapes (X) to colours (Y):
(image from Wikipedia)
The term is also well established in computer science where map()
is a higher order function doing this sort of conversion. In JavaScript, it is an array method and has clear usage - to transform the contents of one array into another. Given array X = [0, 5, 8, 3, 2, 1]
we can apply x => x + 1
to it using the .map()
method.
(Image from Wikipedia)
This is more wide-reaching than just the specifics of the implementation - .map()
is idiomatic and if misused makes code harder to read and understand. Let's do a step-by step example:
We need a mapping function that expresses the relationship between elements. For example, transforming a letter to its position in the alphabet can be expressed via the function:
function letterToPositionInAlphabet(letter) {
return letter.toUpperCase().charCodeAt(0) - 64;
}
Mapping an array of letters via this function will give us an array with each of their positions:
function letterToPositionInAlphabet(letter) {
return letter.toUpperCase().charCodeAt(0) - 64;
}
const letters = ["a", "b", "c"];
console.log(letters.map(letterToPositionInAlphabet));
Is it legit to use .map() method only for side-effects?
So the question, is this legit? Should I avoid this and use a classic for() loop or a .forEach() method?
If you aren't returning anything from the map function, then you should use forEach
instead. You end up with the same result but you don't imply, to anyone maintaining your code, that you are returning something useful.
one of the reasons I'm asking this is because I need to perform some loops on an async function so promises and await operators are involved, I remember that forEach() loops are not ideal on an async function, but wanted to know why.
Neither forEach
nor map
will await
if the function you pass to it returns a promise (which async
functions do).
So there are three possible scenarios here:
// Your loop
...myItemsArray...
// Code that comes after the loop
...etc...
A: The items in the loop need to handled sequentially
Use a regular for ()
loop as the outer function won't pause.
B: The items in the loop can be handled in parallel and the code that comes after doesn't need to wait for it
Use a forEach
.
C: The code that comes after needs to wait for everything in the loop to finish
Use a map
. Pass the array of returned promises to Promise.all
. Then await
that.
How to push response in nested onject
Array.map
function creates a new array populated with the results of calling a provided function on every element in the calling array. So the callback inside map
should return an item and on your code, nothing is returned on callback.
In your case, it's better to use Array.forEach
as follows.
const d = [{
"dashId": 3,
"dashName": "one",
"dashData": []
},
{
"dashId": 4,
"dashName": "two",
"dashData": [{
"nestedId": 1,
"nestedData": "how are you"
}]
}
];
const res = [{
"nestedId": 11,
"nestedData": "I am fine"
}];
d.forEach(li => {
if (li.dashId === 3) {
li.dashData.push(...res)
}
});
console.log(d);
How to overload the Set Class
You don't need all of these fancy features; just this
:
Set.prototype.addMultiple = function(x) {
for (let x of arguments) {
this.add(x);
}
return this;
}
While we're at it, let's use const
instead in the loop:
for (const x of arguments) {
And also arguments
? That's some 2010 code. Nowadays we use spread/variadic arguments:
Set.prototype.addMultiple = function (...args) {
for (const x of args) { ... }
// rest omitted
}
Keep in mind that extending/modifying native prototypes is generally frowned upon, so you're better off extending the class instead.
using .map() instead of .forEach for creating an object
// mapper simply creates the object that you want from the one that you have - id as the key and min and max are the values
const mapper = ({ id, minimum: min, maximum: max }) => ({ [id]: { min, max } });
const obj = data.reduce((acc, obj) => ({
...acc,
...mapper(obj)
}), {});
EDIT:
While reduce is the right way to do this - you are reduceing an array to a single thing, JavaScript allows you various ways to do things. Here's an alternate solution using map and Object.assign
:
const mapper = ({ id, minimum: min, maximum: max }) => ({ [id]: { min, max } });
const obj = Object.assign(...data.map(mapper));
Related Topics
How to Join Two JavaScript Objects, Without Using Jquery
How to Filter by Object Property in Angularjs
Nested Element (Web Component) Can't Get Its Template
What Is Array Literal Notation in JavaScript and When Should You Use It
Create an Empty Object in JavaScript with {} or New Object()
Can't Trigger Click with Jquery in a Chrome Extension
Is There a Generic Way to Set State in React Hooks? How to Manage Multiple States
How to Create a Jquery Clock/Timer
React Js: Uncaught (In Promise) Syntaxerror: Unexpected Token < in JSON at Position 0
Spring Boot Controller - Upload Multipart and JSON to Dto
Unique Object Identifier in JavaScript
Random Number Generator Without Dupes in JavaScript
How to Get All of the Ids with Jquery
How to Get a Specific Parameter from Location.Search
JavaScript - How to Make This Code Work