手写filter()/map()/forEach()/reduce()

filter()/map()/reduce()都是es6新增的对于数组的方法,本篇文章来记录手写这3个函数以及forEach()的过程

filter()方法

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

filter翻译过来就是过滤器的意思[].filter(function(currentValue,index,arr), thisValue),它接受2个参数:
function(currentValue,index,arr): 必须传入的函数,每个数组元素都会执行这个函数,currentValue是当前元素,index是序号,arr是对应的整个数组
thisValue: 对象作为该执行回调时使用,传递给函数,用作 "this" 的值。
具体用法:

// 返回大于等于18的值
let arr = [32, 33, 16, 40].filter((num) => {return num >= 18})
console.log(arr)


手写实现

   Array.prototype.myFilter = function(callback, thisArg) {
     // 确认调用者必须是个数组
     if (Object.prototype.toString.call(this) !== '[object Array]') {
       throw new TypeError('this must be a array');
     }
     // 确认传入的第一个参数必须是函数且存在
     if (typeof callback !== 'function') {
       throw new TypeError(callback + 'is not a function');
     }
     // 返回结果的数组
     const res = [];
     // 让O成为回调函数的对象传递(强制转换对象)
     const O = Object(this);
     console.log(O)
     // >>>0 保证len为number,且为正整数
     // 无符号位移计算符
     const len = O.length >>> 0;
     // 对整个数组进行遍历
     for (let i = 0; i < len; i++) {
         // 遍历回调函数调用传参
         // call是传入(新this指向,参数)
         // thisArg新设置的this,这里无设置就是undefined
         // O[i] 是原数组的当前元素
         // i是当前index
         // O是原数组
         if (callback.call(thisArg, O[i], i, O)) {
           res.push(O[i]);
         }
     }
     // 返回结果
     return res;
   }
   console.log([30,20,16,10].myFilter((num) => { return num >= 12}));

根据上面的数组[30,20,16,10],O就是原数组,每次都判断每个数是否大于等于12,如果大于,就通过if (callback.call(thisArg, O[i], i, O))的判断,并且存入res数组,最后返回的是经过过滤的数组。

map()

map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

map() 会对所有的数据进行处理,[].filter(function(currentValue,index,arr), thisValue)接受的参数和filter()一样。
function(currentValue,index,arr): 必须传入的函数,每个数组元素都会执行这个函数,currentValue是当前元素,index是序号,arr是对应的整个数组
thisValue: 对象作为该执行回调时使用,传递给函数,用作 "this" 的值。

// 对每个值进行*2处理
let arr = [32, 33, 16, 40].map((num) => {return num * 2})
console.log(arr)


手写实现

Array.prototype.myMap = function(callback, thisArg) {
  if (this == undefined) {
    throw new TypeError('this is null or not defined');
  }
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function');
  }
  const res = [];
  const O = Object(this);
  const len = O.length >>> 0;
  for (let i = 0; i < len; i++) {
     // 调用回调函数并传入新数组
     res[i] = callback.call(thisArg, O[i], i, O);
  }
  return res;
}

可以看见map()filter()的实现方式基本一致,无非是filter()多了一个if (callback.call(thisArg, O[i], i, O))的判断,从而实现过滤的效果

forEach()

forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。

使用方法[].forEach(function(currentValue, index, arr), thisValue)
function(currentValue,index,arr): 必须传入的函数,每个数组元素都会执行这个函数,currentValue是当前元素,index是序号,arr是对应的整个数组
thisValue: 对象作为该执行回调时使用,传递给函数,用作 "this" 的值。

手写实现

Array.prototype.myForEach = function(callback, thisArg) {
  // 判断是否是数组调用,并且传入的是回调函数
  if (this == null) {
    throw new TypeError('this is null or not defined');
  }
  if (typeof callback !== "function") {
    throw new TypeError(callback + ' is not a function');
  }
  const O = Object(this);
  const len = O.length >>> 0;
  let k = 0;
 // 循环所有数据  
 for(let i = 0; i < len; i++) {
  callback.call(thisArg, O[k], k, O);
 }
}

forEach()map()就更像了,但是查看源码forEach()是直接在原数组上操作返回undefined,而map()是返回个新数组。
同时还有以下区别:

  1. forEach()的速度更快
  2. map()因为返回数组所以可以链式操作,forEach()不能
  3. map()里可以用return,而foreach里用return不起作用,forEach()也不能使用break/continue

reduce()

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

使用方法array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
function(total, currentValue, currentIndex, arr):必要参数,用于执行每个数组元素的函数 total是计算结束后的返回值,currentValue当前元素,currentIndex当前元素的索引,arr元素所属的数组对象
initialValue:传递的初始值

console.log([1,2,3].reduce((t,num) => {return t + num}))
console.log([1,2,3].reduce((t,num) => {return t + num},5))

手写实现

Array.prototype.myReduce = function(callback, initialValue) {
     // 判断调用的是否是数组,以及传入的callback是否是函数
     if (this == undefined) {
       throw new TypeError('this is null or not defined');
     }
     if (typeof callback !== 'function') {
       throw new TypeError(callbackfn + ' is not a function');
     }
     // 空数组也是不允许的
     if (this.length == 0) {
      throw new TypeError('Reduce of empty array with no initial value');
     }
     // 让O成为回调函数的对象传递(强制转换对象)
     const O = Object(this);
     // >>>0 保证len为number,且为正整数
     const len = this.length >>> 0;
     // 保存初始值,初始值不传的时候为undefined
     let accumulator = initialValue;
     // 标志位
     let k = 0;
     // 如果第二个参数为undefined的情况,则数组的第一个有效值作为累加器的初始值
     if (accumulator === undefined) {
       // 这里是k++,就是赋值完成之后k再加1
       accumulator = O[k++];
     }
     // 此时如果有初始值,k是0,如果无初始值k是1
     for(k;k{return t+n}));
   console.log([2,4,6].myReduce((t,n)=>{return t+n},10));

要确认不能是空数组、必须是数组调用、callback必须是函数这3个条件,之后就是循环执行了,理解起来还是很容易的,多看几遍代码就能了解

你可能感兴趣的:(手写filter()/map()/forEach()/reduce())