29 数组相关

1 实现forEach方法

    Array.prototype.myForEach = function(callback, context=window) {
      // this=>arr
      let self = this,  
          i = 0,
          len = self.length;
    
      for(;i<len;i++) {
        typeof callback == 'function' && callback.call(context,self[i], i)
       }
    }

2 实现filter方法

    Array.prototype.myFilter=function(callback, context=window){
    
      let len = this.length
          newArr = [],
          i=0
    
      for(; i < len; i++){
        if(callback.apply(context, [this[i], i , this])){
          newArr.push(this[i]);
        }
      }
      return newArr;
    }

3 实现find方法

  • find 接收一个方法作为参数,方法内部返回一个条件
  • find 会遍历所有的元素,执行你给定的带有条件返回值的函数
  • 符合该条件的元素会作为 find 方法的返回值
  • 如果遍历结束还没有符合该条件的元素,则返回 undefined
    var users = [
      {id: 1, name: '张三'},
      {id: 2, name: '张三'},
      {id: 3, name: '张三'},
      {id: 4, name: '张三'}
    ]
    
    Array.prototype.myFind = function (callback) {
      // var callback = function (item, index) { return item.id === 4 }
      for (var i = 0; i < this.length; i++) {
        if (callback(this[i], i)) {
          return this[i]
        }
      }
    }
    
    var ret = users.myFind(function (item, index) {
      return item.id === 2
    })
    
    console.log(ret)

4 实现findIndex方法

    var users = [
      {id: 1, name: '张三'},
      {id: 2, name: '张三'},
      {id: 3, name: '张三'},
      {id: 4, name: '张三'}
    ]
    
    Array.prototype.myFindIndex = function (callback) {
      // var callback = function (item, index) { return item.id === 4 }
      for (var i = 0; i < this.length; i++) {
        if (callback(this[i], i)) {
          // 这里返回
          return i
        }
      }
    }
    
    var ret = users.myFind(function (item, index) {
      return item.id === 2
    })
    
    console.log(ret)

5 实现map方法

  • 回调函数的参数有哪些,返回值如何处理
  • 不修改原来的数组
    Array.prototype.myMap = function(callback, context){
      // 转换类数组
      var arr = Array.prototype.slice.call(this),//由于是ES5所以就不用...展开符了
          mappedArr = [], 
          i = 0;
    
      for (; i < arr.length; i++ ){
        // 把当前值、索引、当前数组返回去。调用的时候传到函数参数中 [1,2,3,4].map((curr,index,arr))
        mappedArr.push(callback.call(context, arr[i], i, this));
      }
      return mappedArr;
    }

6 实现reduce方法

  • 初始值不传怎么处理
  • 回调函数的参数有哪些,返回值如何处理。
    Array.prototype.myReduce = function(fn, initialValue) {
      var arr = Array.prototype.slice.call(this);
      var res, startIndex;
    
      res = initialValue ? initialValue : arr[0]; // 不传默认取数组第一项
      startIndex = initialValue ? 0 : 1;
    
      for(var i = startIndex; i < arr.length; i++) {
        // 把初始值、当前值、索引、当前数组返回去。调用的时候传到函数参数中 [1,2,3,4].reduce((initVal,curr,index,arr))
        res = fn.call(null, res, arr[i], i, this); 
      }
      return res;
    }

7 实现every方法

    Array.prototype.myEvery=function(callback, context = window){
        var len=this.length,
            flag=true,
            i = 0;
    
        for(;i < len; i++){
          if(!callback.apply(context,[this[i], i , this])){
            flag=false;
            break;
          } 
        }
        return flag;
      }
    
    
      // var obj = {num: 1}
      // var aa=arr.myEvery(function(v,index,arr){
      // 	return v.num>=12;
      // },obj)
      // console.log(aa)

8 实现some方法

    Array.prototype.mySome=function(callback, context = window){
     			var len = this.length,
     			    flag=false,
               i = 0;
    
     			for(;i < len; i++){
    				if(callback.apply(context, [this[i], i , this])){
    					flag=true;
    					break;
    				} 
     			}
     			return flag;
    		}
    
    		// var flag=arr.mySome((v,index,arr)=>v.num>=10,obj)
    		// console.log(flag);

9 实现数组扁平化flat方法

题目描述: 实现一个方法使多维数组变成一维数组

    let ary = [1, [2, [3, [4, 5]]], 6];
    let str = JSON.stringify(ary);

第0种处理:直接的调用

    arr_flat = arr.flat(Infinity);

第一种处理

    ary = str.replace(/(\[|\])/g, '').split(',');

第二种处理

    str = str.replace(/(\[\]))/g, '');
    str = '[' + str + ']';
    ary = JSON.parse(str);

第三种处理:递归处理

    let result = [];
    let fn = function(arr) {
      for(let i = 0; i < arr.length; i++) {
        let item = arr[i];
        if (Array.isArray(arr[i])){
          fn(item);
        } else {
          result.push(item);
        }
      }
    }

第四种处理:用 reduce 实现数组的 flat 方法

    function flatten(ary) {
        return ary.reduce((pre, cur) => {
            return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
        }, []);
    }
    let ary = [1, 2, [3, 4], [5, [6, 7]]]
    console.log(flatten(ary))

第五种处理:能用迭代的思路去实现

    function flatten(arr) {
      if (!arr.length) return;
      while (arr.some((item) => Array.isArray(item))) {
        arr = [].concat(...arr);
      }
      return arr;
    }
    // console.log(flatten([1, 2, [1, [2, 3, [4, 5, [6]]]]]));

第六种处理:扩展运算符

    while (ary.some(Array.isArray)) {
      ary = [].concat(...ary);
    }

10 实现Array.isArray方法

    Array.myIsArray = function(o) {
      // 调用顶级对象上的toString方法转成[object Array]形式
      return Object.prototype.toString.call(o) === '[object Array]';
    };
    
    console.log(Array.myIsArray([])); // true

11 实现Array.of方法

Array.of()方法用于将一组值,转换为数组

  • 这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。
  • Array.of()基本上可以用来替代Array()new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一
    Array.of(3, 11, 8) // [3,11,8]
    Array.of(3) // [3]
    Array.of(3).length // 1

实现

    function ArrayOf(){
      return [].slice.call(arguments);
    }

12 数组去重方法汇总

首先:我知道多少种去重方式

1. 双层 for 循环

    function distinct(arr) {
        for (let i=0, len=arr.length; i<len; i++) {
            for (let j=i+1; j<len; j++) {
                if (arr[i] == arr[j]) {
                    arr.splice(j, 1);
                    // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一
                    len--;
                    j--;
                }
            }
        }
        return arr;
    }

思想: 双重 for 循环是比较笨拙的方法,它实现的原理很简单:先定义一个包含原始数组第一个元素的数组,然后遍历原始数组,将原始数组中的每个元素与新数组中的每个元素进行比对,如果不重复则添加到新数组中,最后返回新数组;因为它的时间复杂度是O(n^2),如果数组长度很大,效率会很低

2. Array.filter() 加 indexOf/includes

    function distinct(a, b) {
        let arr = a.concat(b);
        return arr.filter((item, index)=> {
            //return arr.indexOf(item) === index
            return arr.includes(item)
        })
    }

思想: 利用indexOf检测元素在数组中第一次出现的位置是否和元素现在的位置相等,如果不等则说明该元素是重复元素

3. ES6 中的 Set 去重

    function distinct(array) {
       return Array.from(new Set(array));
    }

思想: ES6 提供了新的数据结构 Set,Set 结构的一个特性就是成员值都是唯一的,没有重复的值。

4. reduce 实现对象数组去重复

    var resources = [
        { name: "张三", age: "18" },
        { name: "张三", age: "19" },
        { name: "张三", age: "20" },
        { name: "李四", age: "19" },
        { name: "王五", age: "20" },
        { name: "赵六", age: "21" }
    ]
    var temp = {};
    resources = resources.reduce((prev, curv) => {
     // 如果临时对象中有这个名字,什么都不做
     if (temp[curv.name]) {
     
     }else {
        // 如果临时对象没有就把这个名字加进去,同时把当前的这个对象加入到prev中
        temp[curv.name] = true;
        prev.push(curv);
     }
     return prev
    }, []);
    console.log("结果", resources);

这种方法是利用高阶函数 reduce 进行去重, 这里只需要注意initialValue得放一个空数组[],不然没法push

13 对象数组如何去重

根据每个对象的某一个具体属性来进行去重

    const responseList = [
      { id: 1, a: 1 },
      { id: 2, a: 2 },
      { id: 3, a: 3 },
      { id: 1, a: 4 },
    ];
    const result = responseList.reduce((acc, cur) => {
        const ids = acc.map(item => item.id);
        return ids.includes(cur.id) ? acc : [...acc, cur];
    }, []);
    console.log(result); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]

14 数组中的数据根据key去重

给定一个任意数组,实现一个通用函数,让数组中的数据根据 key 排重:

    const dedup = (data, getKey = () => {} ) => {
      // todo
    }
    let data = [
      { id: 1, v: 1 },
      { id: 2, v: 2 },
      { id: 1, v: 1 },
    ];
    
    // 以 id 作为排重 key,执行函数得到结果
    // data = [
    //   { id: 1, v: 1 },
    //   { id: 2, v: 2 },
    // ];

实现

    const dedup = (data, getKey = () => { }) => {
        const dateMap = data.reduce((pre, cur) => {
            const key = getKey(cur)
            if (!pre[key]) {
                pre[key] = cur
            }
            return pre
        }, {})
        return Object.values(dateMap)
    }

使用

    let data = [
        { id: 1, v: 1 },
        { id: 2, v: 2 },
        { id: 1, v: 1 },
    ];
    console.log(dedup(data, (item) => item.id))
    
    // 以 id 作为排重 key,执行函数得到结果
    // data = [
    //   { id: 1, v: 1 },
    //   { id: 2, v: 2 },
    // ];

15 类数组转化为数组的方法

    const arrayLike=document.querySelectorAll('div')
    
    // 1.扩展运算符
    [...arrayLike]
    // 2.Array.from
    Array.from(arrayLike)
    // 3.Array.prototype.slice
    Array.prototype.slice.call(arrayLike)
    // 4.Array.apply
    Array.apply(null, arrayLike)
    // 5.Array.prototype.concat
    Array.prototype.concat.apply([], arrayLike)

16 reduce用法汇总

语法

    array.reduce(function(total, currentValue, currentIndex, arr), initialValue);
    /*
      total: 必需。初始值, 或者计算结束后的返回值。
      currentValue: 必需。当前元素。
      currentIndex: 可选。当前元素的索引;                     
      arr: 可选。当前元素所属的数组对象。
      initialValue: 可选。传递给函数的初始值,相当于total的初始值。
    */

reduceRight() 该方法用法与reduce()其实是相同的,只是遍历的顺序相反,它是从数组的最后一项开始,向前遍历到第一项

1. 数组求和

    const arr = [12, 34, 23];
    const sum = arr.reduce((total, num) => total + num);
    
    // 设定初始值求和
    const arr = [12, 34, 23];
    const sum = arr.reduce((total, num) => total + num, 10);  // 以10为初始值求和
    
    
    // 对象数组求和
    var result = [
      { subject: 'math', score: 88 },
      { subject: 'chinese', score: 95 },
      { subject: 'english', score: 80 }
    ];
    const sum = result.reduce((accumulator, cur) => accumulator + cur.score, 0); 
    const sum = result.reduce((accumulator, cur) => accumulator + cur.score, -10);  // 总分扣除10分

2. 数组最大值

    const a = [23,123,342,12];
    const max = a.reduce((pre,next)=>pre>cur?pre:cur,0); // 342

3. 数组转对象

    var streams = [{name: '技术', id: 1}, {name: '设计', id: 2}];
    var obj = streams.reduce((accumulator, cur) => {accumulator[cur.id] = cur; return accumulator;}, {});

4. 扁平一个二维数组

    var arr = [[1, 2, 8], [3, 4, 9], [5, 6, 10]];
    var res = arr.reduce((x, y) => x.concat(y), []);

5. 数组去重

    实现的基本原理如下:
    
    ① 初始化一个空数组
    ② 将需要去重处理的数组中的第1项在初始化数组中查找,如果找不到(空数组中肯定找不到),就将该项添加到初始化数组中
    ③ 将需要去重处理的数组中的第2项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中
    ④ ……
    ⑤ 将需要去重处理的数组中的第n项在初始化数组中查找,如果找不到,就将该项继续添加到初始化数组中
    ⑥ 将这个初始化数组返回
    var newArr = arr.reduce(function (prev, cur) {
        prev.indexOf(cur) === -1 && prev.push(cur);
        return prev;
    },[]);

6. 对象数组去重

    const dedup = (data, getKey = () => { }) => {
        const dateMap = data.reduce((pre, cur) => {
            const key = getKey(cur)
            if (!pre[key]) {
                pre[key] = cur
            }
            return pre
        }, {})
        return Object.values(dateMap)
    }

7. 求字符串中字母出现的次数

    const str = 'sfhjasfjgfasjuwqrqadqeiqsajsdaiwqdaklldflas-cmxzmnha';
    
    const res = str.split('').reduce((pre,next)=>{
     pre[next] ? pre[next]++ : pre[next] = 1
     return pre 
    },{})
    // 结果
    -: 1
    a: 8
    c: 1
    d: 4
    e: 1
    f: 4
    g: 1
    h: 2
    i: 2
    j: 4
    k: 1
    l: 3
    m: 2
    n: 1
    q: 5
    r: 1
    s: 6
    u: 1
    w: 2
    x: 1
    z: 1

8. compose函数

redux compose 源码实现

    function compose(...funs) {
        if (funs.length === 0) {
            return arg => arg;
        }
        if (funs.length === 1) {
           return funs[0];
        }
        return funs.reduce((a, b) => (...arg) => a(b(...arg)))
    }
Last Updated:
Contributors: leeguooooo