The Red Carpet Fallacy

David de RosierDavid de Rosier
4 min read

Introduction: The Red Carpet Fallacy

JavaScript sometimes is a fashion show. A modern JS codebase is often filled with syntactic sugar, one-liners, and spread operators galore. It's clean. It's concise. It's... slow?

In this post, we're not here to shame your style. But we are here to call out when elegant syntax becomes a performance anti-pattern. Because the truth is: we're not writing for the red carpet – we're writing for the runtime.


Case Study: The Spread-in-Reduce Trap

Imagine we have an array of user records, and we want to convert it into a lookup map by ID:

const users = [
  { id: 'abc', name: 'Alice' },
  { id: 'xyz', name: 'Bob' },
];

A common modern approach looks like this:

const lookup = users.reduce((o, user) => ({ ...o, [user.id]: user }), {});

Clean? Yes. Pure? Definitely. Efficient? Absolutely not.

Every iteration creates a brand new object, copying all existing keys. That means you’re doing O(n²) work for what should be an O(n) task.

✅ Better:

const lookup = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});

It mutates a local object (the accumulator) – a perfectly safe move in this context. It's faster, clearer, and scales as you'd expect.

“But isn't that impure?”

Maybe. But local mutation inside a reduce is not dangerous. And we're not writing Haskell.


🔁 The Great Reverse Debate

Here's another one:

const reversed = [...arr].reverse();

Looks fine, right? But it's two operations:

  • Make a copy with [...arr]
  • Then reverse it in place

✅ Enter toReversed() (ES2023):

const reversed = arr.toReversed();

Same result. But more readable and likely more performant (since it avoids a manual spread + mutation). Plus, it signals intent better: "I want a reversed copy."


✅ When Spread Shines: Clarity, Not Copies

Just to be clear – we're not anti-spread. In fact, it can be the most elegant and performant tool when you're not cloning state blindly.

Take merging arrays:

const combined = [...a, ...b, ...c];

This is expressive, readable, and concise. It clearly states: "take everything from a, b, and c and merge them into one flat array."

Compare that to:

[].concat(a, b, c); // Verbose, less intuitive
[a, b, c].flat();   // Ambiguous intent

Here, the spread operator wins on all fronts: performance, readability, and intent.

Like any tool, it shines when used where it belongs.


⚠️ Fashion Coding vs. Functional Clarity

Let's be clear: we're not here to hate on modern syntax.

We're here to say: use it when it helps. But don't reach for one-liners or spread operators just because they're trendy. Especially when they:

  • Wreck performance
  • Obfuscate intent
  • Hide dangerous behavior behind "elegance"

Code isn't fashion. It's communication. And runtime behavior is part of readability.


📊 Benchmarks

We put our claims to the test using performance.now() in the browser. Here's what we found when running each snippet 1000 times:

Spread vs. Mutation in Reduce

const arr = Array.from({ length: 10000 }, (_, i) => ({ id: `id${i}`, value: i }));

// Slow
arr.reduce((o, item) => ({ ...o, [item.id]: item }), {});

// Fast
arr.reduce((o, item) => {
  o[item.id] = item;
  return o;
}, {});

Reduce with spread: ~900–1200ms
Reduce with mutation: ~4–10ms

Spread Reverse vs. toReversed()

const flatArr = Array.from({ length: 10000 }, (_, i) => i);

// Slower
[...flatArr].reverse();

// Faster and clearer
flatArr.toReversed();

[...arr].reverse(): ~1.7ms
toReversed(): ~1.4ms

Numbers vary by browser and machine, but the orders of magnitude are consistent. Especially in the reduce case, a "fashionable" one-liner can completely wreck performance.


✍️ Final Word

Write code with intention. Know when you're choosing clarity. Know when you're choosing performance. And when you can – choose both.

Make it obvious. Make it fast. Pick both when you can.


This post is co-authored by two devs who’ve seen too much – and written too much – and are now just trying to save a few CPUs from unnecessary cloning.

0
Subscribe to my newsletter

Read articles from David de Rosier directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

David de Rosier
David de Rosier

I’m David. I design systems, teach ideas, and write operating systems for fun (in assembly, because why not). I’ve worked in banks, taught JavaScript to Java developers, deployed software over a satellite, and written code that talks to real hardware and code that talks back. I’m not here to teach. I’m here to think out loud – and maybe help others do the same. If you like RISC-V, Rust, Assembly (little-endian only), metaphors, or words that boot with purpose, you’re in the right place.