Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript JavaScript Array Iteration Methods Combining Array Methods Nested Data and Additional Exploration

Joseph Michelini
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Joseph Michelini
Python Development Techdegree Graduate 18,692 Points

Why does my code still work without providing the .reduce() method an initialValue?

I was wondering why the code below is still working, in VS Code anyway, without providing the .reduce() method an initialValue. Should I have to for this to work?

const bookTitles = users
  .map((user) => user.favoriteBooks.map((book) => book.title))
  .reduce((arr, titles) => [...arr, ...titles]);

console.log(bookTitles);

My output is:

[
  'The Iliad',
  'The Brothers Karamazov',
  'Tenth of December',
  'Cloud Atlas',
  'One Hundred Years of Solitude',
  'Candide'
]

Thanks in advance!

2 Answers

Brandon White
seal-mask
MOD
.a{fill-rule:evenodd;}techdegree seal-36
Brandon White
Treehouse Moderator

Hi Joseph Michelini,

When you don’t provide the reduce method an initialValue, it uses the first element in the array as the accumulator on the first iteration, and skips the currentValue.

See here:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Syntax

Joseph Michelini
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Joseph Michelini
Python Development Techdegree Graduate 18,692 Points

Thanks Brandon, for some reason I thought it would be returning strings in this case but it is in fact returning an array of arrays, setting the accumulator data type to an array like you mentioned. Thanks for your help!

Doron Geyer
seal-mask
.a{fill-rule:evenodd;}techdegree
Doron Geyer
Full Stack JavaScript Techdegree Student 13,841 Points

Joseph Michelini just as note on your question here, you should always add an initial value unless you have a very specific use case reason not to.

If initialValue is provided in the call to reduce(), then accumulator will be equal to initialValue, and currentValue will be equal to the first value in the array. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.

Note: If initialValue is not provided, reduce() will execute the callback function starting at index 1, skipping the first index. If initialValue is provided, it will start at index 0.

If the array is empty and no initialValue is provided, TypeError will be thrown.

If the array only has one element (regardless of position) and no initialValue is provided, or if initialValue is provided but the array is empty, the solo value will be returned without calling callback.

It is almost always safer to provide an initialValue, because there can be up to four possible output types without initialValue, as shown in the following example:

let maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
let maxCallback2 = ( max, cur ) => Math.max( max, cur );

// reduce without initialValue
[ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ); // NaN
[ { x: 2 }, { x: 22 }            ].reduce( maxCallback ); // 22
[ { x: 2 }                       ].reduce( maxCallback ); // { x: 2 }
[                                ].reduce( maxCallback ); // TypeError

// map & reduce with initialValue; better solution, also works for empty or larger arrays
[ { x: 22 }, { x: 42 } ].map( el => el.x )
                        .reduce( maxCallback2, -Infinity );

so in the first example. because you dont have an initial value set the value returned on the first run through causes the last run through to fail. Just as an example of what can go wrong.