For a discussion of what const means (as well as let and var) check out (about half way down the post): https://app.roll20.net/forum/permalink/6255896/
Probably easiest to understand by talking about the Map and Reduce operations in general. Map and Reduce are two of the most important operations for manipulating data in modern computer science. Whole systems are built that only perform Map and Reduce (Such as Hadoop). Underscore JS has a pretty good simple example of each here: https://underscorejs.org/#map
Note that map and reduce haven't always had native support in the Javascript language, which is why there are _.map() and _.reduce() functions in Underscore.js. I'll talk about them in general and then give a simple example in Underscore syntax and Javascript ES6 syntax.
Map
The Map operations is "Map a Function across a Collection of Data and return a new Collection with the Result of the Function). Mathematically, you'd probably write it something like map(f,[a,b,c]) ::= [f(a),f(b),f(c)] or some such (Help me out, Jakob!).
Practically speaking, Map takes an array of values and returns and array of the result of calling a function on those values. The classic example is squaring a list of integers. You could write it out with a loop like this:
let data = [1,2,3,4,5];
let result = [];
for(let i = 0; i < data.length; ++i){
result.push( data[i] * data[i] );
}
log(result);
With Map, you can do it more succinctly (ES6):
let data = [1,2,3,4,5];
let result = data.map( function( value ) { return value * value; });
log(result);
or (Underscore.js):
let data = [1,2,3,4,5];
let result = _.map( data, function( value ) { return value * value; });
log(result);
The beauty of this is that you don't necessarily need to write the function where you're calling it, so
const getLen = ( s ) => s.length;
let data = ['bob', 'nancy', 'sue', 'paul', 'tom'];
let result = data.map(getLen);
log(result);
Just remember that Map will return a collections where the elements are transformed by a supplied function.
Reduce
The Reduce operation is "Reduce a Collection of Data to the Result of a Function applied successively to itself and the next element of Data." That's a little wordy, but mathematically, it's something like reduce(f,[a,b,c],m) ::= f(f(f(m,a),b),c) (or something like that.. Jakob? =D).
Practically speaking, Reduce takes a collection of values and returns some accumulated value. The classic example is summing a list of integers. You could do it with a loop:
let data = [1,2,3,4,5];
let result = 0;
for(let i = 0; i < data.length; ++i){
result = result + data[i];
}
log(result);
With Reduce, you can do it more succinctly (ES6):
let data = [1,2,3,4,5];
let result = data.reduce( function(m, value) { return m + value; }, 0 );
log(result);
or (Underscore.js):
let data = [1,2,3,4,5];
let result = _.reduce( data, function(m, value) { return m + value; }, 0 );
log(result);
Reduce is very powerful because it doesn't just have to build numbers, it can build any sort of value:
let data = [1,2,3,4,5];
let oddEven = data.reduce( (m, v) => { m[v%2 ? 'even':'odd'].push(v); return m;}, { odd:[],even:[]});
log(oddEven);
Most often when you see Reduce, it's to build a new collection in a new format from an old collection.
Syntax
Map takes a collection and a function to apply ES6's map only operates on arrays, Underscores will work on arrays or objects (basically, key:value):
let RESULT = ARRAY.map( FUNCTION );
let RESULT = _.map( ARRAY|OBJECT , FUNCTION );
The function is passed the several arguments, usually you just deal with the first one, the value:
function( VALUE, INDEX, ARRAY )
And must return the new value for that index. (Note that the original collection is not modified.)
Reduce is slightly more complicated. It takes a collection, a function and an initial value (called a memo).
let RESULT = ARRAY.reduce( FUNCTION, MEMO );
let RESULT = _.reduce( ARRAY|OBJECT, FUNCTION, MEMO );
And it's function is passed the return of the prior call of the function (or the memo value if this is the first execution), the value, the index, and the collection, but you usually only deal with the first two:
function( MEMO, VALUE, INDEX, COLLECTION );
Must always return the next memo value, which becomes the final result. If you ever have an error with a reduce not working, it's almost always that you didn't return the memo.
Reduce has one more thing to be aware of. If you don't supply a memo to the initial call, the first value of the collection is used instead. I could have written the sum call above as:
let result = data.reduce( function(m, value) { return m + value; });
and gotten the same result.
Edit: Supplemental ninja by Scott! =D
Edit, the second: BTW, all these code samples should work in the Roll20 API Sandbox, so feel free to experiment with them!