DEV Community

Cover image for Demystifying Array.prototype.flat
Laurie
Laurie

Posted on • Originally published at tenmilesquare.com

Demystifying Array.prototype.flat

ES2019 is officially available for us all to play with. Caution ahead, make sure that if you use these features your browser and/or transpiler supports them.

Without further ado, let's dive into our first new feature. I give you Array.prototype.flat!

The Old Way

Embedded arrays exist in our code for any number of reasons, and to be honest, they're kind of a pain.

let arr = [1, 2, [3, 4, [5, 6]]]
Enter fullscreen mode Exit fullscreen mode

Handling stuff like this used to require unintuitive trickery like the code below.

var merged = [].concat.apply([], arr);
Enter fullscreen mode Exit fullscreen mode

And that would only result in one level of depth being flattened!

[1, 2, 3, 4, [5, 6]]
Enter fullscreen mode Exit fullscreen mode

Boooooooo

The New Way!

Then along came flat(). And this is a game changer.

Doing the same thing we did above is a breeze.

var merged = arr.flat(1)
Enter fullscreen mode Exit fullscreen mode

That argument is just the depth that we want to flatten. So one level deep gets us this, just like before.

[1, 2, 3, 4, [5, 6]]
Enter fullscreen mode Exit fullscreen mode

Note that if you don't pass an argument it defaults to 1. That means these statements are equivalent.

arr.flat(1)
//is the same as
arr.flat()
Enter fullscreen mode Exit fullscreen mode

Magic

But what is so incredibly powerful is that it doesn't stop there. We can flatten our entire array in a single line.

var merged = arr.flat(2)
Enter fullscreen mode Exit fullscreen mode

Becomes

[1, 2, 3, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

Wait for It

We've even been gifted one more awesome feature. Let's say we don't know the depth of our array but we want to flatten it all the way.

var merged = arr.flat(Infinity)
Enter fullscreen mode Exit fullscreen mode

Ron Swanson saying what the hell just happened

In Summary

It's a miracle!!! Go forth and enjoy the awesomeness that ES2019 has gifted us.

Top comments (33)

Collapse
 
terabytetiger profile image
Tyler V. (he/him)

Just saw .flat(Infinity) in the wild for the first time - I only knew what it did because of this article.

Laurie once again saves me time 💕

Collapse
 
laurieontech profile image
Laurie

Someone used it?!? This is my white whale lol

Collapse
 
terabytetiger profile image
Tyler V. (he/him)

I can DM it to you - Idk how much it'll make sense without all the context (which I don't know how much I can share), but I was also excited to see it!

Collapse
 
georgecoldham profile image
George • Edited

Also maybe worth mentioning that

arr.flat()

is the same as

arr.flat(1)

not Infinity as one might expect.

Collapse
 
turnerj profile image
James Turner • Edited

Interesting - without looking at the docs or anything, I would have (incorrectly) assumed:

arr.flat()

was to to flatten all the way down like Laurie's last example

arr.flat(Infinity)
Collapse
 
georgecoldham profile image
George

This is why I thought it should be mentioned. It kept catching me out when I was trying it out.

Thread Thread
 
laurieontech profile image
Laurie

Added :)

Collapse
 
laurieontech profile image
Laurie

Apparently that’s a lot of people’s assumption which actually surprises me!

Thread Thread
 
turnerj profile image
James Turner

I wonder if I am thinking of it similar to how substr works with the second argument.

"abc".substr(1)
"abc".substr(1, Infinity)

These both return "bc" and you don't need to worry about actually specifying the end of the string. I see this in the same way as flat(), it just seems like the more appropriate way of working.

I wonder now what the most common call to flat actually will be, whether it will be specifying a specific level or many just using Infinity.

Collapse
 
laurieontech profile image
Laurie

For sure. Great to point that out.

Collapse
 
maxwell_dev profile image
Max Antonucci

I had no idea that infinity was an option for this! Looking forward to using it, and I'm tempted to argue that should be the default behavior.

My only critique is you should have ended with this GIF :P

Collapse
 
laurieontech profile image
Laurie

Missed opportunity!

Collapse
 
zakhenry profile image
Zak Henry

There's now a new way to create a stack overflow! 🎉

a = [1,2,3]

b = [4,5,6]

a.push(b)

b.push(a)

a.flat(Infinity) 

// VM185:9 Uncaught RangeError: Maximum call stack size exceeded
//    at Array.flat (<anonymous>)
//    at <anonymous>:9:3

Collapse
 
laurieontech profile image
Laurie

I'm not even sure how you triggered that! I tried the same and ended up with a Circular reference warning and then

[1] 5163 segmentation fault node

when node crashed haha.

Well done!

Collapse
 
zakhenry profile image
Zak Henry

Oh interesting, I just tried this in the Chrome console, thanks for the inspiration :)

Collapse
 
bradtaniguchi profile image
Brad • Edited

Does anyone know why the arr.flat() doesn't automatically use Infinity as the default value? Is it a performance thing or something?

Also, could you ever shoot yourself in the foot with this call, or does it protect me from my own shenanigans?

Collapse
 
zakhenry profile image
Zak Henry

could you ever shoot yourself in the foot with this call, or does it protect me from my own shenanigans?

Yep you can shoot yourself in the foot - if for some reason your array contains circular references .flat(Infinity) will cause a stack overflow.

demo:

a = [1,2,3]

b = [4,5,6]

a.push(b)

b.push(a)

a.flat(Infinity) 

// VM185:9 Uncaught RangeError: Maximum call stack size exceeded
//    at Array.flat (<anonymous>)
//    at <anonymous>:9:3
Collapse
 
laurieontech profile image
Laurie

Depends what the shenanigans are! 🙃

And to be honest, I’m surprised so many people expected it to be infinity by default?

Collapse
 
rhymes profile image
rhymes

It make sense, flat(N) means I have to know exactly how many levels of nesting there are. We're lazy, Infinity should have been the default :P

Collapse
 
manimanis profile image
Mohamed Anis MANI • Edited

To flatten your code in JavaScript you can use the old recursive way.

const flatArray = (arr) => {
  let res = [];
  for (let item of arr) {
    if (item instanceof Array) {
      item = flatArray(item);
      res = res.concat(item);
    } else {
      res.push(item);
    }
  }
  return res;
}
Collapse
 
karataev profile image
Eugene Karataev

I'm nitpicking here, but

arr.flat(1) === arr.flat()

is false.

flat returns a new array and since objects (arrays) are compared by reference, any comparison of two arrays located in different memory slots will always return false.

Collapse
 
laurieontech profile image
Laurie • Edited

Thanks for catching that.
That was me throwing it in really quick when someone asked me to make that distinction clear. Shouldn't have used code highlighting/syntax to explain it. I'll adjust!

Collapse
 
rivayudha profile image
Riva Yudha

Indeed it’s a handy feature to work with. But please be careful when using it in production, as my app often crashes in some of my user’s mobile browser, most likely because the browser support is not really good.

This made me had to revert some functions back to use the old ways in order to flattening arrays. Hopefully the browser support is getting better, though.

Collapse
 
jnschrag profile image
Jacque Schrag

.flat is amazing and that Infinity argument is 🔥. Hopefully Edge will eventually get on board and support it natively soon. 🤞

Collapse
 
sobhardwaj profile image
Siddharath shankar bhardwaj

wonderful awesome features.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.