js深入理解forEach map every some filter reduce使用方法及浏览器源码实现

前言

这几个方法都是js5里面最常用,性价比最高的方法,熟练使用的话可以精简掉很多代码,提高代码可读性,还可以链式调用.废话不多说,让我们开始吧!

forEach

forEach实例

let arr=[
  {user:'zs',age:20},
  {user:'ls',age:30},
  {user:'ww',age:40},
  {user:'zl',age:50},
];
function fn(){
  return arr.forEach((item,idx,arr)=>{
    console.log(item,idx);
    if(idx==2){return ;}
    item.age+=idx;
  });
}
let res=fn();
console.log(arr);
console.log(`forEach返回值${res}`);

结果:

//console.log(item,idx)
{ user: 'zs', age: 20 } 0
{ user: 'ls', age: 30 } 1
{ user: 'ww', age: 40 } 2
{ user: 'zl', age: 50 } 3

//console.log(arr)
[ { user: 'zs', age: 20 },
  { user: 'ls', age: 31 },
  { user: 'ww', age: 42 },
  { user: 'zl', age: 53 } ]

//console.log(`forEach返回值${res}`)
forEach返回值undefined

forEach讲解

  • 1.由实例可知forEach参数为回调函数callback, callback有三个参数,分别是 item 每一项 , idx 每一项的索引下标 , arr 调用forEach的原数组
  • 2.如果 item 是基本类型, 无法改变原数组; 如果是引用类型,则会改变原数组
  • 3.在callback函数中调用return, 只会结束当前item项的函数, 不会跳出forEach, 更不会跳出fn函数; 所以如果有判断条件跳出fn函数的需求, 应该使用 for-in 循环
  • 4.callback中不需要写 return xxx; 因为forEach是直接修改原数组, 所以callback中返回没有意义, 注意return 后面的代码不会执行
  • 5.forEach 方法没有返回值
  • 6.注意实例中用的是es6的箭头函数, 所以回调中的this是fn函数的当前上下文; 如果改为es5的 function(){} ,则回调函数中的this是 window|global ,并不是arr
  • 7.总结:forEach方法遍历数组, callback直接修改原数组,callback中可以不返回

forEach浏览器源码实现

if (!Array.prototype.forEach) {
  Array.prototype.forEach = function(callback, thisArg) {
    var T, k;
    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }
    var O = Object(this);
    var len = O.length >>> 0;
    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }
    if (arguments.length > 1) {
      T = thisArg;
    }
    k = 0;
    while (k < len) {
      var kValue;
      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k++;
    }
  };
}

map

map实例

let arr=[
  {user:'zs',age:20},
  {user:'ls',age:30},
  {user:'ww',age:40},
  {user:'zl',age:50},
];
function fn(){
  return arr.map((item,idx,arr)=>{
    console.log(item,idx);
    if(idx==2){return;}
    return item;
  });
}
let res=fn();
console.log(arr);
console.log(res);

结果:

//console.log(item,idx)
{ user: 'zs', age: 20 } 0
{ user: 'ls', age: 30 } 1
{ user: 'ww', age: 40 } 2
{ user: 'zl', age: 50 } 3

//console.log(arr)
[ { user: 'zs', age: 20 },
  { user: 'ls', age: 30 },
  { user: 'ww', age: 40 },
  { user: 'zl', age: 50 } ]

//console.log(res)
[ { user: 'zs', age: 20 },
  { user: 'ls', age: 31 },
  undefined,
  { user: 'zl', age: 53 } ]

map讲解

  • 1.由实例可知map参数为回调函数callback, callback有三个参数,分别是 item 每一项 , idx 每一项的索引下标 , arr 调用map的原数组
  • 2.无论在callback中怎么操作,都不会修改原数组; 只会将结果返回到新数组中
  • 3.在callback函数最后必须调用return item, 否则map返回的数组中对应项为undefined
  • 4.注意实例中用的是es6的箭头函数, 所以回调中的this是fn函数的当前上下文; 如果改为es5的 function(){} ,则回调函数中的this是 window|global ,并不是arr
  • 5.总结:map方法遍历数组, callback直接不修改原数组,返回新数组,callback最后必须return item

map浏览器源码实现

if (!Array.prototype.map) {
  Array.prototype.map = function(callback, thisArg) {
    var T, A, k;
    if (this == null) {
      throw new TypeError(" this is null or not defined");
    }
    var O = Object(this);
    var len = O.length >>> 0;

    if (Object.prototype.toString.call(callback) != "[object Function]") {
      throw new TypeError(callback + " is not a function");
    }
    if (thisArg) {
      T = thisArg;
    }
    A = new Array(len);
    k = 0;
    while(k < len) {
      var kValue, mappedValue;
      //遍历O,k为原数组索引
      if (k in O) {
        //kValue为索引k对应的值.
        kValue = O[ k ];
        // 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
        mappedValue = callback.call(T, kValue, k, O);
        // 返回值添加到新数组A中.
        A[ k ] = mappedValue;
      }
      k++;
    }
    return A;
  };      
}

every

every实例

let arr=[5,6,7,8,9];
let res1=arr.every((item,idx,arr)=>{
  return item>4;
});
let res2=arr.every((item,idx,arr)=>{
  return item>7;
});
console.log(arr);
console.log(res1);
console.log(res2);

结果

//console.log(arr);
[ 5, 6, 7, 8, 9 ]
//console.log(res1);
true
//console.log(res2);
false

every讲解

  • 1.every方法表示遍历数组,判断是否每一项都符合条件,如果是则返回 true, 只要存在不符合条件的项则返回 false
  • 2.由实例可知every参数为回调函数callback, callback有三个参数,分别是 item 每一项 , idx 每一项的索引下标 , arr 调用every的原数组
  • 3.无论在callback中怎么操作,都不会修改原数组; 只会返回Boolean类型值
  • 4.在callback函数最后必须调用return condition, 否则every返回 false
  • 5.注意实例中用的是es6的箭头函数, 所以回调中的this是fn函数的当前上下文; 如果改为es5的 function(){} ,则回调函数中的this是 window|global ,并不是arr

every浏览器源码实现

if (!Array.prototype.every)
{
  Array.prototype.every = function(fun /*, thisArg */)
  {
    'use strict';

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function')
        throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t && !fun.call(thisArg, t[i], i, t))
        return false;
    }

    return true;
  };
}

some

some实例

let arr=[5,6,7,8,9];
let res1=arr.some((item,idx,arr)=>{
  return item>10;
});
let res2=arr.some((item,idx,arr)=>{
  return item>7;
});
console.log(arr);
console.log(res1);
console.log(res2);

结果

//console.log(arr);
[ 5, 6, 7, 8, 9 ]
//console.log(res1);
false
//console.log(res2);
false

some讲解

  • 1.some方法表示遍历数组,判断是否有符合条件的项,如果有则返回 true, 如果没有一项符合条件的项则返回 false
  • 2.由实例可知some参数为回调函数callback, callback有三个参数,分别是 item 每一项 , idx 每一项的索引下标 , arr 调用some的原数组
  • 3.无论在callback中怎么操作,都不会修改原数组; 只会返回Boolean类型值
  • 4.在callback函数最后必须调用return condition, 否则some返回 false
  • 5.注意实例中用的是es6的箭头函数, 所以回调中的this是fn函数的当前上下文; 如果改为es5的 function(){} ,则回调函数中的this是 window|global ,并不是arr

some浏览器源码实现

if (!Array.prototype.some)
{
  Array.prototype.some = function(fun /*, thisArg */)
  {
    'use strict';

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function')
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t && fun.call(thisArg, t[i], i, t))
        return true;
    }

    return false;
  };
}

filter

filter实例

let arr=[5,6,7,8,9];
let res1=arr.filter((item,idx,arr)=>{
  return item%2===0;
});
let res2=arr.filter((item,idx,arr)=>{
  return item>7;
});
console.log(arr);
console.log(res1);
console.log(res2);

结果

//console.log(arr);
[ 5, 6, 7, 8, 9 ]
//console.log(res1);
[ 6, 8 ]
//console.log(res2);
[ 8, 9 ]

filter讲解

  • 1.filter方法表示遍历数组,过滤出符合条件的项,如果有则返回 所有符合条件项组成的数组, 如果没有符合条件的项则返回空数组
  • 2.由实例可知filter参数为回调函数callback, callback有三个参数,分别是 item 每一项 , idx 每一项的索引下标 , arr 调用filter的原数组
  • 3.无论在callback中怎么操作,都不会修改原数组; 只会返回新数组
  • 4.在callback函数最后必须调用return condition, 否则filter返回空数组
  • 5.注意实例中用的是es6的箭头函数, 所以回调中的this是fn函数的当前上下文; 如果改为es5的 function(){} ,则回调函数中的this是 window|global ,并不是arr

filter浏览器源码实现

if (!Array.prototype.filter)
{
  Array.prototype.filter = function(fun /* , thisArg*/)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var res = [];
    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t)
      {
        var val = t[i];
        if (fun.call(thisArg, val, i, t))
          res.push(val);
      }
    }

    return res;
  };
}

reduce和reduceRight

reduce和reduceRight实例

let arr=[1,2,3,4,5];
let res1=arr.reduce((prev,item,idx,arr)=>{
  return prev+item;
},2);
let res2=arr.reduceRight((prev,item,idx,arr)=>{
  return prev+item;
});
console.log(arr);
console.log(res1);
console.log(res2);

结果

//console.log(arr);
[ 1, 2, 3, 4, 5 ]
//console.log(res1);
27
//console.log(res2);
25

reduce和reduceRight讲解

  • 1.reduce和reduceRight都是累加器方法,表示按callback规则累计,可以传入第二个参数作为初始值,返回累加结果
  • 2.由实例可知这两个方法参数为回调函数callback和初始值prev, callback有四个参数,分别是 prev上一次遍历的结果或初始值, item 每一项 , idx 每一项的索引下标 , arr调用的原数组
  • 3.无论在callback中怎么操作,都不会修改原数组; 只会返回累加值
  • 4.在callback函数最后必须调用return expression, 否则返回undefined
  • 5.reduce方法表示从最小下标项到最大累加, reduceRight表示从最大下标项到最小累加
  • 6.注意实例中用的是es6的箭头函数, 所以回调中的this是fn函数的当前上下文; 如果改为es5的 function(){} ,则回调函数中的this是 window|global ,并不是arr

reduce和reduceRight浏览器源码实现

//reduce
if (!Array.prototype.reduce) {
  Array.prototype.reduce = 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');
    }
    var t = Object(this), len = t.length >>> 0, k = 0, value;
    if (arguments.length == 2) {
      value = arguments[1];
    } else {
      while (k < len && !(k in t)) {
        k++;
      }
      if (k >= len) {
        throw new TypeError('Reduce of empty array with no initial value');
      }
      value = t[k++];
    }
    for (; k < len; k++) {
      if (k in t) {
        value = callback(value, t[k], k, t);
      }
    }
    return value;
  };
}

//reduceRight
if ('function' !== typeof Array.prototype.reduceRight) {
  Array.prototype.reduceRight = function(callback /*, initialValue*/) {
    'use strict';
    if (null === this || 'undefined' === typeof this) {
      throw new TypeError('Array.prototype.reduceRight called on null or undefined');
    }
    if ('function' !== typeof callback) {
      throw new TypeError(callback + ' is not a function');
    }
    var t = Object(this), len = t.length >>> 0, k = len - 1, value;
    if (arguments.length >= 2) {
      value = arguments[1];
    } else {
      while (k >= 0 && !(k in t)) {
        k--;
      }
      if (k < 0) {
        throw new TypeError('ReduceRight of empty array with no initial value');
      }
      value = t[k--];
    }
    for (; k >= 0; k--) {
      if (k in t) {
        value = callback(value, t[k], k, t);
      }
    }
    return value;
  };
}

(写的不对的欢迎指正, 有问题可以留言探讨!)

猜你喜欢

转载自blog.csdn.net/lyt_angularjs/article/details/80466366