这是我参与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 = node.value;
node = idsMap[arr[i].id];
}
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: []
}
idsMap[parentNode.id] = parentNode;
}
parentNode.children.push(node);
}
}
return res;
}
console.log(convertArrToTree(arr));
看下执行结果:
数组拍平
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')
看一下执行结果:
深度克隆
关于深克隆和浅克隆的多种方法可以看这篇,这里就附上最优解:
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 curry = fn =>
judge = (...args) =>
fn.length === args.length? fn(...args): (...newArgs) => judge(...args, ...newArgs)
函数组合
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);