柯里化reduce

1,610 阅读1分钟

实现reduce

reduce:累加器(accumulator)

// 判断非空
const isDef = function(o){
  return o !== undefined && o !== null
}

/**
 * fn 函数
 * @param { * } total 初始值(计算结束后的返回值)
 * @param { * } currentValue 当前元素
 * @param { Number } currentIndex 当前元素的索引
 * @param { Array } arr 当前元素所属的数组对象
 */
 
// Array的prototype声明$reduce
Array.prototype.$reduce = function(fn, tar){
  let len = this.length, // 目标数组长度
      res, // 数组
      i = 0; // 初始index
  if (isDef(tar)) {
    // 有第二个参数,total为初始值
    res = tar
  } else {
    // 没有第二个参数,初始值为数组第一项
    res = this[0]
    // 由于第一项为初始值,就从第二项开始累计
    i++
  }
  // 循环数组
  while (i < len) {
    // 把算的值传入fn第一个参数
    res = fn(res, this[i], i++, this)
  }
  return res
}

应用

[1, 2, 3, 4, 5].$reduce((total, currentValue, currentIndex, arr) => {
  console.log(total, currentValue, currentIndex, arr)
  return total + currentValue;
}, 0) // => 15

// 0 1 0 [ 1, 2, 3, 4, 5 ]
// 1 2 1 [ 1, 2, 3, 4, 5 ]
// 3 3 2 [ 1, 2, 3, 4, 5 ]
// 6 4 3 [ 1, 2, 3, 4, 5 ]
// 10 5 4 [ 1, 2, 3, 4, 5 ]

函数式编程封装(纯函数)

返回一个函数,把this改为返回函数的参数(arr)

// reduce : ((a, b) → a) → a → [b] → a
const reduce = function(fn, tar){
  const _isDef = function(o){
    return o !== undefined && o !== null
  }
  return function(arr){
    let len = arr.length,
        res,
        i = 0;
    if (_isDef(tar)) {
      res = tar
    } else {
      res = arr[0]
      i++
    }
    while (i < len) {
      res = fn(res, arr[i], i++, arr)
    }
    return res
  }
}
// 求和
const sum = reduce((a, b) => a + b, 0)
sum([1, 2, 3, 4, 5]) // 15

// 求乘积
const product = reduce((a, b) => a * b)
product([1, 2, 3, 4, 5]) // 120

// 求对象数组某元素的某一项和
const inSum = reduce((a, { score }) => a + score, 0)
inSum([{ score: 1 }, { score: 2 }, { score: 3 }]) // 6

ps. 函数式编程最好的参考书: legacy.gitbook.com/book/llh911…