常用工具函数

·  阅读 73

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

前言

很多同学们都应该遇到过手写某些功能函数的情况,这篇文就来做一个简单的整理~

数组转化成树

给定一个数组,根据id规则转化成树

//数组转化为树
let arr = [
    {id: 1, value: 12},
    {parentId: 1, id: 2, value: 13},
    {id: 3, value: 14},
    {parentId: 3, id: 4, value: 15}
 ];


function convertArrToTree(arr) {
    let res = [];
    let idsMap = {};
    let len = arr.length;
    let parentNode;

    for(let i=0; i<len; i++) {
        let node = {
            id: arr[i].id,
            children: [],
            value: arr[i].value
        }

        if(!idsMap[arr[i].id]) {
            idsMap[arr[i].id] = node;    //引用赋值,idsMap修改会影响node,从而影响res
        }else {   //已经存在了,直接赋值即可
            idsMap[arr[i].id].value = value;
        }


        if(!arr[i].parentId) {
            res.push(node);
        }else {
            if(idsMap[arr[i].parentId]) {
                parentNode = idsMap[arr[i].parentId];  //parentNode修改同步影响idsMap
            }else {
                parentNode = {
                    id: arr[i].parentId,
                    children: []
                }
            }
            parentNode.children.push(node);
        }
    }

    return res;
}

console.log(convertArrToTree(arr));
复制代码

看下执行结果:

image.png

数组拍平

Array.reduce方式实现

function flat1(arr) {
   return arr.reduce(function(pre, cur){
      return pre.concat(Array.isArray(cur) ? flat1(cur) : cur);
   }, []);
}
复制代码

循环实现

function flat2(arr) {
   let result = [];
   let stack = [].concat(arr);

   while(stack.length > 0) {
      let val = stack.pop();
      if(Array.isArray(val)) {
         stack.push(...val);
      }else {    //将当前项插入队列最前边
         result.unshift(val);
      }
   }
   return result;
}
复制代码

字符串实现

function flat3(arr) {
   return arr.toString().split(',');
}
复制代码

多个任务并行执行

实现一个任务队列,可以同时最多执行3个任务;当其中一个任务执行完成,执行下一个任务。

class Scheduler {
   constructor() {
      this.tasks = []
      this.runningTaskCount = 0
      this.resolveArr = []
   }
   add(promiseCreator) {
      this.tasks.push(promiseCreator)
      return new Promise((resolve) => {
         this.resolveArr.push(resolve)
         this.run()
      })
   }
   run() {
      if (this.runningTaskCount < 3 && this.tasks.length > 0) {
         this.runningTaskCount++
         const resolveFn = this.resolveArr.shift()
         const task = this.tasks.shift()
         task().then(() => {
            this.runningTaskCount--
            resolveFn()
            this.run()
         })
      }
   }
}



const timeout = (time) => new Promise(resolve => {
   setTimeout(resolve, time)
})

const scheduler = new Scheduler()

const addTask = (time, order) => {
   scheduler.add(() => timeout(time)).then(() => console.log(order))
}

addTask(1000, '1')
addTask(500, '2')
addTask(500, '3')
addTask(300, '4')
addTask(400, '5')
addTask(100, '6')
复制代码

看一下执行结果:

image.png

深度克隆

关于深克隆和浅克隆的多种方法可以看这篇,这里就附上最优解:

function cloneDeep(obj) {
    let visitedMap = new WeakMap();

    function baseClone(target) {
        if(typeof target === 'object' && target) {
            if(visitedMap.get(target)) {   //已经记录过
                return visitedMap.get(target);
            }

            let result = Array.isArray(target) ? [] : {};
            visitedMap.set(target, result);

            const keys = Object.keys(target);
            for(let i=0; i<keys.length; i++){
                result[keys[i]] = baseClone(target[keys[i]]);
            }

            return result;

        }else {
            return target;
        }
    }

    return baseClone(obj);
}
复制代码

实现reduce函数

reduce接收两个参数:回调函数(cb)和初始值(initval)

cb回调又包含四个参数:

  • acc: 累积器,上一次回调的累积值。

  • cur:当前处理的数组元素

  • i:当前处理的数组元素索引

  • arr: 原始数组

Array.prototype.myReduce = function(cb, initVal) {
   let arr = this;
   let acc = initVal || arr[0];
   let startIdx = initVal? 0:1;

   for(let i=startIdx; i<arr.length; i++) {
      let cur = arr[i];
      acc = cb(acc, cur, i, arr);
   }

   return acc;

}
复制代码

函数柯里化

function curry(fun) {
   return function curried() {
      let args = Array.prototype.slice.call(arguments);    //类数组转化为数组;
      if(args.length < fun.length) {   //说明还在传参输入,未执行
         console.log(fun.length);
         return function() {
            let innerArgs = Array.prototype.slice.call(arguments);
            let allParams = args.concat(innerArgs);

            return curried.apply(this, allParams)
         }

      }else {
         return fun.apply(this, args);
      }
   }
}

function add(a,b,c,d) {
   console.log(a+b+c+d);
   return a+b+c+d;
}

let f1 = curry(add);
f1(1)(2)(3)(4);
复制代码

函数组合

const compose = (...fns) => {
   console.log(fns);
   return (...args) => {
      let res = args;

      for(let i=0; i<fns.length; i++) {
         res = fns[i](res);
      }
      return res;
   }
}

const f = compose(( x=> Number(x)+1),(x => x+2),(x => x+3))
f(1);
复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改