首页 使用递归实现 ES5 中的数组方法 reduce
文章
取消

使用递归实现 ES5 中的数组方法 reduce

1. 递归

JavaScript高级程序设计(第三版) 第7章中的7.1节讲了 递归

1.1 递归函数

递归函数是在一个函数通过名字调用自身的情况下构成的。

书中给了一个经典的递归阶乘函数:

1
2
3
4
5
6
7
function factorial(num) {
  if(num <= 1) {
    return 1;
  } else {
    return num * factorial(num - 1);
  }
}

可以看到此函数通过函数名factorial调用了自身。JavaScript中关于函数,可以这样理解:
函数名是指针,函数是对象。
这样,如果我们把其它值赋值给了factorial后,就会导致出错:

1
2
3
var anotherFactorial = factorial;
factorail = null;
anotherFactorial(4);// 出错

factorial的值为null,所以anotherFactorial函数中调用factorial函数时,就会报错。

1.2 arguments.callee

arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用。

1
2
3
4
5
6
7
function factorial(num) {
  if(num <= 1) {
    return 1;
  } else {
    return num * arguments.callee(num - 1);// 重点
  }
}

但在严格模式下,不能通过脚本访问arguments.callee

1.3 命名函数表达式

1
2
3
4
5
6
7
var factorial = (function f(num) {
  if(num <= 1) {
    return 1;
  } else {
    return num * f(num - 1);// 重点
  }
});

以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial。这种方式在严格模式和非严格模式下都行得通。

2. 实现数组方法reduce

2.1 reduce

reduce() 为 ES5 中数组的一个方法,它会从数组的第一项开始,迭代数组的所有项,然后构建一个最终返回值。
此方法接收两个参数:

  • 1) 在每一项上调用的函数,格式为:
    1
    2
    3
    4
    
    function (prev, curr, index, array) { 
    // 进行一些操作,然后返回一个结果
    return result;
    }
    

    其中:

    • prev: 前一个值;
    • curr: 当前值;
    • index: 项的索引;
    • array: 数组对象。
  • 2) 作为归并基础的初始值(可选)。
    • 有初始值时,第一次执行函数时,prev 为初始值,curr 为数组第一项;
    • 无初始值时,第一次执行函数时,prev 为数组第一项,curr 为数组第二项;

书中的例子:

1
2
3
4
5
var arr = [1,2,3,4,5];
var sum = arr.reduce(function(prev, curr, index, array){
  return prev + curr;
})
console.log(sum); // 15

2.2 如何实现reduce

给数组 Array 的原型添加一个自定义方法 _myReduce:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Array.prototype._myReduce = function (func, init) {
  let i = 0;
  let _this = this;
  // 命名函数表达式
  var merge = (function f(prevRes) {
    const res = func(prevRes, _this[i], i, _this);
    if (i >= _this.length - 1) {
      return res;
    } else {
      i++;
      return f(res);
    }
  });
  if (init == undefined) {
    // 无初始值
    if(this.length === 1) {
      // 数组长度为1
      return this[0];
    }
    return merge(_this[i++]);// i++ : 先使用,然后加1
  } else {
    // 有初始值
    return merge(init);
  }
}

使用:

1
2
3
4
5
6
7
8
9
let arr = [1,2,3,4,5];
const res1 = arr._myReduce((prev, curr) => {
  return prev + curr;
});
const res2 = arr._myReduce((prev, curr) => {
  return prev + curr;
}, 100);
console.log('res1 = ', res1);// 15
console.log('res2 = ', res2);// 115
本文由作者按照 CC BY 4.0 进行授权