Is Performing a Mapping Operation Without Using Returned Value an Antipattern

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):

"One type of map is a function, as in the association of any of the four colored shapes in X to its color in Y." --description from Wikipedia
(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.

"View of processing steps when applying map function on a list" --description from Wikipedia
(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



Leave a reply



Submit