Rajat Saxena
Rajat Saxena

Reputation: 3925

Why won't the function work?

So, I am going through "JavaScript Allonge" and there is this function, to simulate array's .length function:

const length = ([first, ...rest]) =>
  first === undefined
    ? 0
    : 1 + length(rest);

Now, if I re-write the function as:

var lengthy = (first, ...rest) => 
    first === undefined ? 0 : 1 + lengthy(rest)

It gives, Maximum call stack size exceeded, Why? I called my version like this:

lengthy(1)

Upvotes: 0

Views: 96

Answers (3)

Pineda
Pineda

Reputation: 7593

var lengthy = ([first, ...rest]) => first === undefined ? 0 : 1 + lengthy(rest)
// lengthy gets passed ONE argument, an array

This most likely because first is never evaluating to 0 which causes an infinite loop.

length accepts ONE argument which is an array.

lengthy accepts an arbitrary number of arguments, and counts them, but when you are calling it recursively you are only passing it ONE.

So when lengthy is called for the second time, ...rest is undefined and is passed in the recursive call to lengthy which means first will from then on only be undefined and cause your error.

Upvotes: 1

trincot
trincot

Reputation: 350272

You need to use the spread syntax in the recursive call, otherwise you will pass an array as first argument, and the rest argument will then be an empty array. This will go on endlessly.

So do:

var lengthy = (first, ...rest) => 
    first === undefined ? 0 : 1 + lengthy(...rest);    
    
console.log(lengthy(1,2,3,8,11));

Note that on the initial call rest is an array, which has all the remaining arguments in it. In the example above, rest will be [2,3,8,11]. This is what the rest syntax does for you.

Now you can see how your recursive call would look of you would not spread that array again:

 lengthy(rest)

...becomes

 lengthy([2,3,8,11]) 

So now the arguments in the recursive call are:

 first = [2,3,8,11]
 rest = []

If you continue this analysis, you'll see the next call is with:

 first = []
 rest = []

And this will go on for ever.

Now with the correction lengthy(...rest), the actual call will be in the example:

 lengthy(2,3,8,11) 

... which is what you want. Now the next value of first and rest will be:

 first = 2
 rest = [3,8,11]

...etc.

Upvotes: 3

Andrew Eisenberg
Andrew Eisenberg

Reputation: 28757

The answer has to do with destructuring.

In the original, you have:

([first, ...rest])

In the second answer, you have:

(first, ...rest)

The original takes a single array as an argument, and destructures the array so that the first element is in first and the remaining are in rest.

The second does not destructure the array and plops the array that you pass in into first, leaving rest to be an empty array. This is called recursively. And on all recursive calls to lengthy, rest is never empty.

Upvotes: 2

Related Questions