DEV Community

Samantha Ming
Samantha Ming

Posted on

Passing Arrays as Function Arguments

Code Tidbit by SamanthaMing.com

If you want to pass an array into a variadic function. You can use ES6 spread to turn that array into a list of arguments. Yay, so much cleaner and no useless null from the old apply way ๐Ÿ‘

function sandwich(a, b, c) { 
  console.log(a) // '๐Ÿž'
  console.log(b) // '๐Ÿฅฌ'
  console.log(c) // '๐Ÿฅ“'
}

const food = ['๐Ÿž', '๐Ÿฅฌ', '๐Ÿฅ“'];

// Old way
sandwich.apply(null, food);

// โœ… ES6 way
sandwich(...food);

Using it with Math functions

The ability to turn an array into a list of arguments is super handy with the Math functions.

Example: Find the Largest Number

Let's say you want to find the largest number using the Math.max() function.

const largest = Math.max(5, 7, 3, 4);

console.log(largest); // 7

But rarely, would you pass in individual values. More likely, you would want to find the maximum element in an array. So the question now is, how do you pass an array of values into a function that accepts individual arguments and NOT an array?

This would be terrible:

const numbers = [5, 7, 3];

// ๐Ÿคฎ Yuck!
Math.max(numbers[0], numbers[1], numbers[2]);

// โŒ And this won't work
Math.max(numbers); // NaN

Lucky for us, we can use ES6's Spread operator!

const numbers = [5, 7, 3];

// ๐Ÿ˜ Much Better!
Math.max(...numbers); // 7

What spread is doing here is taking the array element and expanding or unpacking it into a list of arguments for our variadic function.

const numbers = [5, 7, 3];

console.log(...numbers); // 5 7 3 

Explaining spread in non-dev terms

If you find this spread-ing thing still confusing. Maybe let me try to explain it with Russian nesting dolls. So I like to think of the array as Russian nesting dolls. And what spread does is:

  1. It unpacks (spread) the nested dolls into individual dolls.
  2. And now you have all these individual dolls (arguments) to place nicely in your display case (function).

Not sure if this explanation helps? Leave a comment if it does, and I'll start explaining programming concepts in fun ways like this ๐Ÿ˜†

Passing Multiple Arrays as Function Arguments

Another superpower spread has is combining arrays.

const one = [1,2,3];
const two = [4,5,6];

const merged = [...one, ...two];
// [ 1, 2, 3, 4, 5, 6 ]

So we can use this superpower to pass multiple arrays as function arguments ๐Ÿ’ช

const one = [1,2,3];
const two = [4,5,6];

Math.max(...one, ...two); // 6

For those keeners, wondering if you can pass in 3 arrays. Well, you betcha! It's like the energizer bunny, it keeps going and going and going .... (This post is not sponsored by Energizer lol. But that can change, hit me up Energizer. Me want some sponsor money ๐Ÿ˜‚)

const one = [1,2,3];
const two = [4,5,6];
const three = [2,100,2];

Math.max(...one, ...two, ...three); // 100

What is a variadic function?

So you may notice I use the term variadic functions. The computer science folks will have probably heard this term. But for the rest of the cool bees like myself ๐Ÿ˜, it may not be so familiar. A variadic function is a function that accepts an infinite or variable number of arguments. And the Math.max() function is one of those variadic function.

Resources


Thanks for reading โค
Say Hello! Instagram | Twitter | Facebook | Medium | Blog

Top comments (12)

Collapse
 
moopet profile image
Ben Sinclair

TIL function.prototype.apply(). I was looking at your "old way" and thinking, what is she talking about? :)

I guess in Javascript whenever I've wanted to pass in an array it's always been to a function that accepts arrays. I've seen people talk about the spread operator but for functions I'd expect the need to be the other way around (as with C-like functions like printf(), where you'd probably never want to convert an array to a series of parameters)

Collapse
 
qm3ster profile image
Mihail Malo

Do you feel that variadic functions should be used?
Or would you prefer if there were only fixed-length functions, eg if Math.max was split into:

Math.max2 = (a, b) => Math.max(a, b)
Math.maxA = arr => Math.max(...arr)
Collapse
 
onashchuk profile image
Alexey Onashchuk

Funny thing that functions like Math.Max internally receive that arguments as arrays (or array-like objects to be precise)

Collapse
 
toastking profile image
Matt Del Signore

Good ol' this.arguments. My favorite Javascript feature that I'm afraid to use because it doesn't have all the Array methods I want.

Collapse
 
samanthaming profile image
Samantha Ming

It looks like an array, but unfortunately, it isnt :(

Actually, maybe I should write a post about that. The arguments is an interesting topic and I don't think everyone knows that exists ๐Ÿค” Even if they knew, the post will be a nice reminder ๐Ÿ˜‚

Thread Thread
 
qm3ster profile image
Mihail Malo

@samanthaming if you end up writing a post on it, I beg of you to include warnings about performance and analysis implications, as well as the "single rest argument"((...args)) alternative.
Honestly, that's the only way I see to offset the damage of more people finding out about/remembering it :D

Collapse
 
qm3ster profile image
Mihail Malo • Edited

AFAIK it causes deoptimization, while (...args) works much better.
Still, if you expect a real array, like in Math's case, you should just take an array.

Math.max(...new Array(200000).fill(1))
Math.max.apply(undefined,new Array(200000).fill(1))

These both fail with a stack overflow, and the only way to get an answer is to implement it yourself:

new Array(20000000).fill(1).reduce((a,b)=>b>a?b:a)
Collapse
 
samanthaming profile image
Samantha Ming

โ€œArray-likeโ€, thatโ€™s the keyword. I remember I was so confused when I first encountered that ๐Ÿ˜…

Collapse
 
qm3ster profile image
Mihail Malo • Edited

This is problematic because it goes on the stack.

const bite1 = arr => {
  const [head, ...tail] = arr
  if (tail.length === 0) return "โšฐ"
  return bite1(tail)
}
console.log(bite1(new Array(2000))) // Success

const biteV = (...args) => {
  const [head, ...tail] = args
  if (tail.length === 0) return "โšฐ"
  return biteV(...tail)
}
console.log(biteV(...new Array(600))) // DIES

In both cases we are iterating immutably and using lots of memory, but the second runs out of stack space while the first doesn't. (And mere 600 is far from a ridiculous number!)

Collapse
 
sgtino profile image
Stefano Giraldi

The Spread Power!

Thank you, Samantha. This is a useful post! ๐Ÿ‘

Collapse
 
samanthaming profile image
Samantha Ming

Awesome! Glad to hear that, thank you for reading the post :D

Collapse
 
blair2004 profile image
Blair Jersyer

not bad, but i believe, it's so unpredictable this way.