DEV Community

loading...

Spread Operator: don't misuse it

Mukul Jain
Javascript Engineer
・2 min read

Spread operator was introduced with JavaScript ES6 along with other great features, but with great power comes the great responsibility. Mostly it is used to create a new reference to object or an array, though it only copies one level deep it's pretty useful especially where we cannot mutate object like React or Redux state, though we are not creating a whole new object, it gets the work done.

Great! What's the issue then? Enough talk let's write some code, We will be using a user array for this purpose and will create a map of active users. Let's define a simple User interface before jumping to real problem.

interface IUser {
  active: boolean;
  name: string;
  id: string;
}

const users = []; // 10,000 users
Enter fullscreen mode Exit fullscreen mode

Case 1

const activeUsers = users.reduce((acc, user) => {
  if (user.active) {
    return { ...acc, [user.id]: user };
  }
  return acc;
}, {});
Enter fullscreen mode Exit fullscreen mode

Case 2

let activeUsers = {};

users.forEach((user) => {
  if (user.active) {
    result[user.id] = user;
  }
});
Enter fullscreen mode Exit fullscreen mode

Case 3

const a = users.filter((user) => user.active).map((user) => [user.id, user]);
const activeUsers = Object.fromEntries(a);
Enter fullscreen mode Exit fullscreen mode

Can you arrange according their performance? from best to worst.

Check actual stats!

### Result

  1. Case 2
  2. Case 3 (~63% slow)
  3. Case 1 (~86% slow)

Checkout all test cases here: JS Bench

Let's dive in

No surprise case 2 was fasted, just plain loop with simple key value addition.

Case 3 was expected to be slow as it has to iterate the array twice that should slow it down and now we have an idea by what margin so avoid it.

Case 1 was not expected to be this slow as it's similar to case one with builtin method, there is one thing which might be slowing it down, reduce internal implementation!

Nope, it's the spread operator, in general it's slower then adding a key-pair to object but that doesn't mean avoid it just use it only if required. In the case 1 anyway we will get a new object from the reduce using spread operator is totally unnecessary. Change it to

const activeUsers = users.reduce((acc, user) => {
  if (user.active) {
    acc[user.id] = user;
  }
  return acc;
}, {});
Enter fullscreen mode Exit fullscreen mode

and it is almost at par with forEach one, 1% slower.

We might have developed a habit of always using spread operator to avoid uncalled bugs in daily life especially with React and it might not be degrading the performance much but it can, in some cases like this one, so let's remember this, might come handy one it.

Discussion (2)

Collapse
klvenky profile image
Venkatesh KL • Edited

So true. Spreading, destructuring, reduce all are amazing tools. However as someone wise once said "It depends".

Always ensure to use right tool for right job. I've goofed up similarly & wrote an article (Reduce its not my friend anymore) about the same long back.
Wonderful way to say that all that glitters is not gold.
Keep doing great
Cheers 👍

Collapse
alekseiberezkin profile image
Aleksei Berezkin

Thanks for sharing. Case 1 is square complexity thus it's the slowest. Case 3 is linear but creates a lot of intermediate arrays.