loading...
Cover image for Demystifying Array.prototype.flat

Demystifying Array.prototype.flat

laurieontech profile image Laurie Originally published at tenmilesquare.com ・2 min read

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]]]

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

var merged = [].concat.apply([], arr);

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

[1, 2, 3, 4, [5, 6]]

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)

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]]

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

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)

Becomes

[1, 2, 3, 4, 5, 6]

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)

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.

Posted on by:

laurieontech profile

Laurie

@laurieontech

Software dev at Gatsby | DC techie | Conference speaker | egghead Instructor | TC39 Educators Committee | Girls Who Code Facilitator | Board game geek | @laurieontech on twitter

Discussion

pic
Editor guide
 

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 💕

 

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

 

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!

 

Also maybe worth mentioning that

arr.flat()

is the same as

arr.flat(1)

not Infinity as one might expect.

 

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)
 

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

Added :)

 

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

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.

 

For sure. Great to point that out.

 

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

 

Missed opportunity!

 

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

 

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!

 

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

 

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?

 

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
 

Depends what the shenanigans are! 🙃

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

 

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

 

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;
}
 

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.

 

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!

 

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.

 

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

 
 

Really nice breakdown of this new function ❤️ Thanks for sharing

 

Oh that's a great feature!
Thanks for sharing @Laurie

 

Infinity Flatterers

 

That's a great argument. On array!!! C#, JavaScript, Python Computer Programming Language's Instruments Automation Technologies.
Wiltel49@gmail.com
AAS ITI MICHIGAN

 

This is pretty handy... I'm still waiting for modern JS in all Browsers (and IE death maybe)

 

But what if it's nested arrays all the way down?

 

That's what the final example is for :)

arr.flat(Infinity)
 

Object.assign, freeze and seal should had an equivalent for the recursion