Reduce() in depth

后端 未结 3 658
再見小時候
再見小時候 2021-01-22 01:31

In ES5, the new array method reduce(). I am wondering if someone can explain more in depth.

3条回答
  •  说谎
    说谎 (楼主)
    2021-01-22 02:03

    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
      }, {}))
    

提交回复
热议问题