In ES5, the new array method reduce(). I am wondering if someone can explain more in depth.
The method you pass into .reduce
takes parameters previous_returned_value, current_iteration_item, current_iteration_index, context_array
This means that each time it is called, the first argument is the return
value from the previous invocation
The initial value is what is passed in only the very first time.
You can read the MDN docs about it here
return an object form which key is idx and value is Math.pow(idx,2)
e.g.
[1, 2, 3, 4, 5].reduce((o, e) => (o[e] = Math.pow(e, 2), o), {});
// Object {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
count how many letters are are in an array and turn it into the object
So again
['f', 'o', 'o', 'b', 'a', 'r'].reduce((o, e) => (o[e] = (o[e] || 0) + 1, o), {});
// Object {f: 1, o: 2, b: 1, a: 1, r: 1}
Please note the arrow notation functions I've used exploit the comma operator to return what I want, more traditionally you might write the function as e.g. followed by evolution to my examples
function (o, e) {
o[e] = Math.pow(e, 2);
return o;
}
// same as
function (o, e) {
return o[e] = Math.pow(e, 2), o;
}
// similar to
(o, e) => {
return o[e] = Math.pow(e, 2), o;
}
// same as
(o, e) => (o[e] = Math.pow(e, 2), o);
Imagine we have the following code snippet somewhere in our application:
function addLog() {
console.log(arguments)
return arguments[0] + arguments[1]
}
console.log([2,3,4].reduce(addLog))
console.log([2,3,4].reduce(addLog, 1))
Unfortunately we have a dependency on a library called badlibrary.js
which will overwrite ES5's default Array.prototype.reduce
:
badlibrary.js:
Array.prototype.reduce = Infinity
Since this library is a dependency for our application, we cannot remove the library. The only solution is to fix Array.prototype.reduce
by rewriting it before we run our code.
It turns out that this is not so difficult. We can just read Mozilla's documentation on reduce and translate the English to JavaScript.
Array.prototype.reduce = function(callback, initialValue) {
var resultSoFar, i
var n = this.length
if (typeof initialValue !== 'undefined') {
resultSoFar = initialValue
i = 0
} else {
resultSoFar = this[0]
i = 1
}
for (; i < n; i++) {
resultSoFar = callback(resultSoFar, this[i], i, this)
}
return resultSoFar
}
Our code now works, even with this custom version of reduce
, and now reduce
is no longer a "black box". We could easily write it ourselves if we wanted to, and in fact, that is what several people did before ES5 was standardized. By the way, some people still use browsers that only support up to ES3. For reduce
to be truly cross-browser compatible, we still need to shim it or use a utility library like Underscore/Lodash/Ramda. Using a utility library is IMO, the best and easiest solution.
ALSO :) we have an array with lettters. some repeats some don't. I want to count how many letters are are in an array and turn it into the object form. {a:5, .... z:7}; Someone please walk me through with it. I understand forEach and map just fine, but with the reduce method, I am having very difficult time getting my head around it.
The thing we want to return is a JS object with the letters as the keys and their counts as the values. We called this value resultSoFar
in our reduce
function and we are going to build that value up by calling our function on each of the elements of the array. Our initial value should be an empty object. In our function, we'll take the current letter and try to add 1 to its count. If this produces NaN
(which will happen if the count is undefined i.e. when we are seeing a letter for the first time and no count has been assigned yet), then we should assign the value to 1 instead since its a new letter to count and we're seeing one of them.
With this theory in mind, the counting code can be written as follows:
var letters = ['a', 'b', 'c', 'a', 'b', 'a']
console.log(letters.reduce(function(counts, currentLetter) {
var currentLetterCount = counts[currentLetter]
counts[currentLetter] = currentLetterCount + 1 || 1
return counts
}, {}))
The reduce() method is an iterator it loops through all the elements in an array and does something with the results. The reduce() function accepts a callback function. This the function that actually executes whatever you want it to do for every iteration. This function is a special function
the first parameter this function takes is previous value the second parameter this function takes is current value and two other parameters (let just make this simple)
lets consider we have an array
arr=[1,2,3,4,5,6]
using reduce by creating a function called sum
function sum(previousvalue,currentvalue,index,ar){
return previousvalue+currentvalue
}
and finally we place a reference of this function in the reduce method
arr.reduce(sum)
executing this we get 21
What really is this special function doing? let's consider
[1,2,3,4,5,6]
function sum says
Wrong! "let me take the current element value in this array " == 1
Right! # the function starts at the second element in the array so the previous element is the 1st element
"let me add the current element value to the prev. element value in this array and remember this value " == 1+2
"okay I am moving on to the next value"==3
"okay..I will add the next value to the previous summed up value"==3+3
"now I will save this value and do the same thing again until I loop to the end"
But wait what is the practical use of this, I can write this easily without using the reduce function?
It is like a generator function (like in some languages such as python)..it doesn't remember values except the previous call value and the current value...(some memory efficiency advantage)
example finding moving averages
function sum(previousvalue,currentvalue,index,ar){
return (previousvalue+currentvalue/2)
}
the function above is the revision of a the same old funciton i was using
-It takes the first two element find the average and save the value -It takes the next element add it the average and find another average and the cycle goes on