Javascript不清不楚之reduce

reduce

下面这段代码实现来自:MDN - reduce

// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    //callback累加回调函数,initialValue累加初始和
    value: function(callback /*, initialValue*/) {
      if (this === null) {
        throw new TypeError( 'Array.prototype.reduce ' + 
          'called on null or undefined' );
      }
      if (typeof callback !== 'function') {
        throw new TypeError( callback +
          ' is not a function');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length"))(无符号右移)
      var len = o.length >>> 0; 

      // Steps 3, 4, 5, 6, 7      
      var k = 0; 
      var value;

      if (arguments.length >= 2) {
        //如果传入了初始累计和,则将其赋值给value,这时候循环次数和数组的长度相同
        value = arguments[1];
      } else {
        //如果没有传入初始累计和,则调整开始执行回调函数的索引,找到第一个索引值
        while (k < len && !(k in o)) {
          k++; 
        }

        // 3. If len is 0 and initialValue is not present,
        //    throw a TypeError exception(空数组进行reduce操作会报错)
        if (k >= len) {
          throw new TypeError( 'Reduce of empty array ' +
            'with no initial value' );
        }
        value = o[k++];
      }

      // 8. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kPresent be ? HasProperty(O, Pk).
        // c. If kPresent is true, then
        //    i.  Let kValue be ? Get(O, Pk).
        //    ii. Let accumulator be ? Call(
        //          callbackfn, undefined,
        //          « accumulator, kValue, k, O »).
        if (k in o) {
          // 调用回调函数,参数依次为(累计和,当前值,当前索引,数组),回调函数需要返回一个累计和
          value = callback(value, o[k], k, o);
        }

        // d. Increase k by 1.      
        k++;
      }

      // 9. Return accumulator.
      return value;
    }
  });
}

数组累计和

var sum = [0, 1, 2, 3].reduce(function (a, b) {
  return a + b;
}, 0);
// sum is 6

// 等价于下面这种计算,区别是上面的回调函数会执行4次,下面的回调函数会执行3次
var sum = [0, 1, 2, 3].reduce(function (a, b) {
  return a + b;
});

将二维数组转换为一维数组

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
  (a, b) => [...a, ...b]
);
// flattened = [0, 1, 2, 3, 4, 5]

// 记一次面试经历:将[{a:1}, {b:2}, {c:3}]类型的数组转换为[a,b,c,1,2,3]
[{a:1}, {b:2}, {c:3}].reduce((res, item, index) => {
    for(var key in item){
        res.splice(index, 0, key);
        res.push(item[key]);
    }
    return res;
}, []);

数组去重

[5,4,3,2,1,1,2,2,3,4,5,6].reduce((res, value, index) => {
    if(!res.includes(value)){
        res.push(value);
    }
    return res;
}, []);
// [5, 4, 3, 2, 1, 6] 没有改变非重复元素的排列顺序

[5,4,3,2,1,1,2,2,3,4,5,6].sort().reduce((res, value, index) => {
    if(res.length === 0 || res[res.length - 1] !== value){
        res.push(value);
    }
    return res;
}, []);
// [1, 2, 3, 4, 5, 6] 改变了元素的排列顺序

统计数组中元素重复次数

[5,4,3,2,1,1,2,2,3,4,5,6].reduce((res, value, index) => {
    if(!(value in res)){
        res[value] = 1;
    }else{
        ++res[value];
    }
    return res;
}, {});
// {1: 2, 2: 3, 3: 2, 4: 2, 5: 2, 6: 1}

猜你喜欢

转载自blog.csdn.net/qq452981462/article/details/80870807