数组的reduce方法和redux

我们先来看一个题目 :
完成一个flatten数组,实现排平一个js的多维数组为一维,示例如下

  var testArr1 = [[0, 1], [2, 3], [4, 5]];
  var testArr2 = [0, [1, [2, [3, [4,[5]]]]]];
  flatten(testArr1) // [0, 1, 2, 3, 4, 5];
  flatten(testArr2) // [0, 1, 2, 3, 4, 5];

递归

第一个想到的念头肯定是递归,递归自然就想到递归的尽头,那就是判断数组某项元素是否还是数组类型

   var flatten = function(array){
      return array.reduce(function(previous, val){
           if(Object.prototype.toString.call(val) !== '[object Array]'){
               return (previous.push(val), previous);
           }
           return (previous.push(flatten(val)), previous);
      }, []);
   }

我们先来逐步拆分下

return的是什么

我们注意到上面的写法return使用了括号表达式,括号内容的前半部分是为了执行

   function multiply2(){
       var a = 1;
       return (a = a * 2, a);
   }
   multiply2();   // 2

Object.prototype.toString.call

Object.prototype.toString.call在这里只是用来判断是否是数组,在ES5中的isArray 方法的实现就是这样,可以参考另一篇博文js数组应用

    function isArray(o) {
        // 利用参数的toString方法
        return Object.prototype.toString.call(o) === '[object Array]';
    }

reduce方法

reduce方法是ES5引入,使用的场景并不多,但是了解它的特性确实必须的。reduce方法在MDN中的直接描述为: The reduce method applies a function against an accumulator and each value of the array(from left-to-right) to reduce it to a single value。我们来看它的具体使用

   var values = [1, 2, 3, 4, 5];
   var sum = values.reduce(function(prev, cur, index, array){
       return prev + cur;
   })
   alert(sum);

reduce函数接受4个参数: 前一个值,当前值,项的索引和数组对象。这个函数返回的任何值都会做为第一个参数自动传给下一项

分析刚才的函数

结合上面分析,我们就得到了函数的另一个样子。原本我们会使用另一个数组来保存拍平的数组结果,结果reduce函数直接在每次迭代中保存了一个数组。

   var flatten = function(array){
      return array.reduce(function(previous, val){
           if(!Array.isArray(array)){
               //每次previous数组保存了我们每次遍历得到的新结果
               return (previous.push(val), previous);
           }
           //如果是数组,继续递归使用拍平函数,最后还是要返回previous的引用
           return (previous.push(flatten(val)), previous);
      //这里的数组[]为previous的初始值
      }, []);
   }

这个方法写成ES6就是如下形式

   const flatten = array => array.reduce((pre, val)=> pre.concat(!Array.isArray(array) ? val : flatten(val)),[]);

如何实现一个reduce的pollyfill

现在明白了reduce的秘密,接下来我们需要充分发挥对JS的理解,来手动实现一个reduce函数。毕竟,reduce是ES5带来的数组新特性,在不使用ES5-shim的情况下,需要手动兼容。第一种是译者直接用循环写的,第二种直接使用数组的现成方法。

   // 译者方法
   var reduce = function(array, fn, initialvalue){
       var prev = typeof initialvalue == undefined ? array[0] : initialvalue;
       var startPoint = initialvalue ? 1 : 0;
       for(var i = startPoint,len = array.length; i < len; i++){
          prev = fn(prev, array[i], i, array);
       }
       return prev;
   }

   var reduce = function(arr, func, initialValue) {
       var base = typeof initialValue === 'undefined' ? arr[0] : initialValue;
       var startPoint = typeof initialValue === 'undefined' ? 1 : 0;
       arr.slice(startPoint)
          .forEach(function(val, index) {
              base = func(base, val, index + startPoint, arr);
            });
        return base;
   };

译者这里提醒,如果Array.slice 只传入一个参数n的时候,是直接切除n个元素,并一样返回新数组索引,所以可以进行链式调用

   var array = [1, 2, 3];
   var newArray = array.slice(2);  // [3]

ES5-shim的pollyfill

ES5-shim里的pollyfill,跟上面译者方法基本完全一致。

Redux中的reducer

熟悉Redux数据流架构的同学理解reducer做了什么,关于这个纯函数的命名,在redux源码github仓库上也有一个官方解释:“It’s called a reducer because it’s the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue)”,虽然是一笔带过,但是总结的恰到好处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值