安利一波前端面试算法题

4 阅读8分钟
  1. 防抖-连续触发事件只有最后一次触发
function debounce(fn, time) {
  let timer;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      clearTimeout(timer);
      timer = null;
    }, time);
  };
}
  1. 节流-会有冻结时间,连续触发事件在冻结时间内触发的事件无法被触发
function throttle(fn, time) {
  let timer;
  return function () {
    if (timer) return;
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      clearTimeout(timer);
      timer = null;
    }, time);
  };
}
  1. promise相关方法封装
const myProiseAll = (promises) => {
  let count = 0;
  let arr = [];
  return new Promise((res, rej) => {
    promises.forEach((ele, ind) => {
      Promise.resolve(ele)
        .then((i) => {
          arr[ind] = i;
          count += 1;
          if (count === promises.length) {
            res(arr);
          }
        })
        .catch(rej);
    });
  });
};

const myPromiseRace = (promises) => {
  return new Promise((res, rej) => {
    promises.forEach((i) => {
      Promise.resolve(i).then(res, rej);
    });
  });
};

const myPromiseAny = (promises) => {
  let count = 0;
  let arr = [];
  return new Promise((res, rej) => {
    promises.forEach((i, ind) => {
      Promise.resolve(i).then(res, (err) => {
        arr[ind] = { val: err };
        count += 1;
        if (count === promises.length) {
          rej(new Error('........'));
        }
      });
    });
  });
};

const allSettled = (promises) => {
  return new Promise((resolve) => {
    const data: any = [],
        len = promises.length;
    let count = len;
    for (let i = 0; i < len; i += 1) {
      const promise = promises[i];
      promise
        .then(
          (res) => {
            data[i] = res;
          },
          (error) => {
            data[i] = error;
          }
        )
        .finally(() => {
          // promise has been settled
          if (!--count) {
            resolve(data);
          }
        });
    }
  });
};
  1. 数组reduce方法封装
Array.prototype.reduce = function (
  callback: (
    previousValue: U,
    currentValue: T,
    index: number,
    array: T[]
  ) => U,
  initialValue?: U
): U | T {
  const array = this as T[];
  let result: T | U;
  let startIndex = 0;

  if (initialValue !== undefined) {
    result = initialValue;
  } else {
    if (array.length === 0) {
      throw new TypeError('Reduce of empty array with no initial value');
    }
    result = array[0];
    startIndex = 1;
  }

  // 迭代数组
  for (let i = startIndex; i < array.length; i++) {
    result = callback(result as U, array[i], i, this);
  }
  return result;
};
  1. 批量加载图片
let urls = [
  'https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg',
  'https://www.kkkk1000.com/images/getImgData/gray.gif',
  'https://www.kkkk1000.com/images/getImgData/Particle.gif',
  'https://www.kkkk1000.com/images/getImgData/arithmetic.png',
  'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif',
  'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg',
  'https://www.kkkk1000.com/images/getImgData/arithmetic.gif',
  'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/10/29/166be40ccc434be0~tplv-t2oaga2asx-image.image',
];
function loadImg(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = function () {
      console.log('一张图片加载完成');
      document.body.append(img);
      resolve();
    };
    img.onerror = reject;
    img.src = url;
  });
}
async function limitLoad(urls, loadImg, limit) {
  // 复制urls数组
  const sequence = [...urls];
  // 存储正在执行的promise
  const promises = new Array(limit).fill(null);

  // 初始化:先并发执行limit个任务
  for (let i = 0; i < limit; i++) {
    if (sequence.length) {
      promises[i] = loadImg(sequence.shift());
    }
  }

  // 处理剩余的任务
  for (const url of sequence) {
    // 等待最快的任务完成
    const fastestIndex = await Promise.race(
      promises.map((promise, index) => promise.then(() => index))
    );

    // 替换已完成的任务位置
    promises[fastestIndex] = loadImg(url);
  }

  // 等待所有任务完成
  return Promise.all(promises);
}
limitLoad(urls, loadImg, 3)
  .then((res) => {
    console.log('图片全部加载完毕');
    console.log(res);
  })
  .catch((err) => {
    console.error('err==>', err);
  });
  1. 去除字符串空格
const str' H e l l o , W o r l d ! ';
const noSpacesStr = str.split('').filter((char) => char !== ' ').join('');
  1. 深度拷贝对象
const obj = {  
    arr: [],
    a: 1,
   };
obj.sub = obj;
obj.arr.push(obj);
function deepCopy(value, map = new Map()) {
    if (value === null || typeof value !== 'object') {      
        return value;    
    }    
    if (map.has(value)) {     
        return map.get(value);
    } 
    const res = Array.isArray(value) ? [] : {};    
    map.set(value, res);    
    for (let key in value) {
        res[key] = _deepCopy(value[key]);   
    }
    return res
}
deepCopy(obj);
  1. 判断多维数组嵌套层级
const arr = [1,[2,[3,4,[5,6]]]]

//方法一
const getMaxDepth = (arr)=>{  
    if(!Array.isArray(arr)){    
        return 0
    }  
    if(arr.length === 0){
        return 0;
    }  
    let maxChildDepth0;
    for(const item of arr) {
        const childDepth = getMaxDepth(item)
        maxChildDepth = Math.max(maxChildDepth,childDepth) 
    }
    return maxChildDepth+=1
}

//方法二
const getMaxDepth = (arr) => {
    const res = [];

    const loop = (item, ind) => {
      res[ind] = (res[ind] || 0) + 1;
      item.forEach((i) => {
        if (Array.isArray(i)) {
          loop(i, ind);
        }
      });
    };

    arr.forEach((item, ind) => {
      if (Array.isArray(item)) {
        loop(item, ind);
      } else {
        res[ind] = 0;
      }
    });

    const num = Math.max(...res) + 1;

    return num;
  };
}

  1. 俩数之和
// 示例   const nums = [2, 7, 11, 15];   const target = 9;  输出0和1
const twoSum = (num,target) => {
    const obj = {};
    for(let i=0;i {
  let maxArr = [];
  let stempArr = [];

  let i = 0;
  while (i < str.length) {
    const char = str[i];
    if (!stempArr.includes(char)) {
      stempArr.push(char);
      i++;
    } else {
      if (maxArr.length < stempArr.length) {
        maxArr = [...stempArr];
      }
      // 找到重复字符的位置并调整窗口
      const duplicateIndex = stempArr.indexOf(char);
      stempArr = stempArr.slice(duplicateIndex + 1);
      stempArr.push(char);
      i++;
    }
  }

  if (maxArr.length < stempArr.length) {
    maxArr = [...stempArr];
  }

  console.log('maxArr==', maxArr.join(''));
  return maxArr.join('');
};

lengthOfLongestSubstring('abcadbecf')
//方法二:双指针
const lengthOfLongestSubstring = (str) => {
  let left = 0,
    right = 0,
    maxLngth = 0;

  let map = new Map();

  while (right <= str.length) {
    const char = str[right];
    if (map.has(char)) {
      left = map.get(char) + 1;
    }

    map.set(char, right);
    maxLngth = Math.max(right - left, maxLngth);
    right++;
  }
  console.log(maxLngth);
};
  1. 数组排序
//冒泡排序
const lengthOfLongestSubstring = (arr) => {
    for (let i = 0; i < arr.length - 1; i++) {
      for (let j = 0; j < arr.length - 1 - i; j++) {
        if (arr[j] > arr[j + 1]) {
          let temp = arr[j];
          arr[j] = arr[j + 1];
          arr[j + 1] = temp;
        }
      }
    }

    return arr;
};

const arr = [2, 1, 5, 3, 23, 2, 3, 6, 9];

lengthOfLongestSubstring(arr);

//选择排序
const arr = [1, 2, 19, 12, 21, 13, 8, 4];

const fn = (arr) => {
    for (let i = 0; i < arr.length; i++) {
        let min = i;
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[min]) {
               min = j;
            }
        }
        [arr[i], arr[min]] = [arr[min], arr[i]];
    }
    return arr;
};

const res = fn(arr);

//数组快排
const quickSort = (arr) => {
    if (arr.length <= 1) {
        return arr;
    }

    const pivotIndex = Math.floor(arr.length / 2);
    const pivot = arr[pivotIndex];
    const left = [];
    const right = [];
    
    for (let i = 0; i < arr.length; i++) {
        if (i === pivotIndex) {
            continue;
        }

        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    return [...quickSort(left), pivot, ...quickSort(right)];
};

const arr = quickSort([12, 1, 2, 33, 5, 11, 23, 21]);

//数组原地快排
const quickSort = (arr, start = 0, end = arr.length - 1) => {
    if (start < end) {
        const midInd = getMidInd(arr, start, end);
        quickSort(arr, start, midInd - 1);
        quickSort(arr, midInd + 1, end);
    }
    return arr;
};

// 获取中间索引
const getMidInd = (arr, left, right) => {
    const lastVal = arr[right];  // 选择最后一个元素作为基准数
    let start = left; // 记录小于基准数的元素应该放置的位置
    for (let i = left; i < right; i++) {
        const element = arr[i];
        if (element < lastVal) {
            // 将小于基准数的元素交换到左侧区域
            [arr[start], arr[i]] = [arr[i], arr[start]];
            start++; // 左侧区域边界右移
        }
    }
    // 将基准值放到正确的位置上(左侧小于它的元素和右侧大于等于它的元素之间)
    [arr[right], arr[start]] = [arr[start], arr[right]];

    return start; // 返回基准值的最终位置
};

console.log(quickSort([2, 33, 41, 23, 13, 53]));
  1. 链表反转
const lengthOfLongestSubstring = (head) => {
  let current = head;
  let prev = null;
  while (current) {
    let tempNext = current.next;
    current.next = prev;
    prev = current;
    current = tempNext;
  }

  while (prev) {
    console.log(prev.val);
    prev = prev.next;
  }
  return prev;
};

const node = {
  val: 1,
  next: {
    val: 2,
    next: {
      val: 3,
      next: {
        val: 4,
        next: {
          val: 5,
          next: null,
        },
      },
    },
  },
};

lengthOfLongestSubstring(node);
  1. 找出数组中加和等于目标值的最短数组组合
//例如给定如下一个目标值和一个数组
const target = 7,
numbers = [2, 3, 0, 4, 1, 3];
// 找数组最短组合
// 写个函数输出3,因为[3,0,4]是最短数组组合

const fn = (target, numbers) => {
    let resArr = [];
    let startInd = 0;
    
    while (startInd < numbers.length) {
        let i = startInd;
        let tempArr = [];
        while (i < numbers.length) {
            if (tempArr.reduce((a, b) => a + b, 0) < target) {
            tempArr.push(numbers[i]);
        }
        if (
            tempArr.reduce((a, b) => a + b, 0) == target &&
            (resArr.length == 0 || resArr.length > tempArr.length)
        ) {
            resArr = tempArr;
            break;
        } else if (tempArr.reduce((a, b) => a + b, 0) > target) {
            break;
        }
            i++;
        }
        startInd++;
    }
    return resArr.length;
};

const a = fn(target, numbers);
console.log(a);

14、数组flat方法

const arr = [1, 2, [5, 6, 7]];

const fn = (arr) => {
  const carr = [];

  const loop = (arr) => {
    arr.forEach((i) => {
      if (Array.isArray(i)) {
        loop(i);
      } else {
        carr.push(i);
      }
    });
  };
  loop(arr);
  console.log('carr==>', carr);
  return carr;
};

fn(arr);

15.求字符串最多出现次数的字符

const str = 'abcabbbas';

const fn = (str) => {
  const obj = {};
  for (let i = 0; i < str.length; i++) {
    if (obj[str[i]]) {
      obj[str[i]]++;
    } else {
      obj[str[i]] = 1;
    }
  }

  const max = {
    val: '',
    count: 0,
  };

  for (const key in obj) {
    if (obj[key] > max.count) {
      max.count = obj[key];
      max.val = key;
    }
  }
  console.log(max);
  return max.count;
};

fn(str);

16、实现一个拖拽效果


<div id="content"></div>

  const dom = document.getElementById('content');
  const body = document.getElementsByTagName('body')[0];
  dom.addEventListener('mousedown', (e) => {
    const mouseupFn = (e) => {
      body.removeEventListener('mousemove', mousemoveFn);
    };

    const mousemoveFn = (e) => {
      const { pageX, pageY } = e;
      dom.style.left = pageX - 50 + 'px';
      dom.style.top = pageY - 50 + 'px';
      dom.addEventListener('mouseup', mouseupFn);
    };

    body.addEventListener('mousemove', mousemoveFn);
  });



    .container {
      width: 400px;
      height: 400px;
      border: 2px dashed #ccc;
      padding: 20px;
    }

    .draggable {
      width: 100px;
      height: 100px;
      background: #2196f3;
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: move;
      margin: 10px;
      transition: opacity 0.3s;
    }

    .dragging {
      opacity: 1;
    }
  
  
    <div class="container">
      <div class="draggable">拖拽元素 1</div>
    </div>
    
      // 获取所有可拖拽元素
      // const draggables = document.querySelectorAll('.draggable');
      const draggable =
        document.getElementsByClassName('draggable')[0];

      // 绑定拖拽开始事件
      draggable.addEventListener('dragstart', handleDragStart);
      // 拖拽结束事件处理,清理状态
      draggable.addEventListener('dragend', handleDragEnd);

      // 容器绑定放置事件
      const container = document.querySelector('.container');
      // 在目标区域悬停时持续触发,必须阻止默认行为才能触发 drop
      container.addEventListener('dragover', handleDragOver);
      // 在目标区域释放时触发,处理放置逻辑
      container.addEventListener('drop', handleDrop);

      // 当前被拖拽的元素
      let draggedElement = null;

      // 拖拽开始事件处理
      function handleDragStart(e) {
        draggedElement = this;
        this.classList.add('dragging');

        // 设置拖拽数据(可传递自定义数据)
        e.dataTransfer.setData('text/plain', '传递拖拽数据');
      }

      // 拖拽悬停事件处理(必须阻止默认)
      function handleDragOver(e) {
        e.preventDefault(); //必须阻止默认行为才能触发drop事件
      }

      // 放置事件处理
      function handleDrop(e) {
        // e.preventDefault();

        // 获取拖拽数据
        const data = e.dataTransfer.getData('text/plain');
        console.log('拖拽数据:', data);

        // 计算新位置
        const rect = container.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;

        // 更新元素位置
        draggedElement.style.position = 'absolute';
        draggedElement.style.left = x - 50 + 'px'; // 居中偏移
        draggedElement.style.top = y - 50 + 'px';
      }

      // 拖拽结束事件处理
      function handleDragEnd() {
        this.classList.remove('dragging');
        draggedElement = null;
      }
    

17、数组转树

let flatArr = [
    { id: 1, title: '1', pid: 0 },
    { id: 2, title: '2', pid: 0 },
    { id: 3, title: '2-1', pid: 2 },
    { id: 4, title: '3-1', pid: 3 },
    { id: 5, title: '4-1', pid: 4 },
    { id: 6, title: '2-2', pid: 2 },
];

const fn = (flatArr) => {
    let map = new Map();

    flatArr.forEach((i) => {
        map.set(i.id, { ...i, children: [] });
    });

    let tree = [];

    flatArr.forEach((i) => {
        let node = map.get(i.id);
        let parent = map.get(i.pid);
        if (parent) {
            parent.children.push(node);
        } else {
            tree.push(node);
        }
    });
        console.log('tree:', tree, '====', JSON.stringify(tree));
};

fn(flatArr);

18、斐波拉契数列(爬楼梯,每次爬1个或者2个)

function fn(num) {
  if(num<=2) return 1;
  return fn(num-1)+fn(num-2);
}

--------

const fn = (n) => {
    if (n < 2) {
        return n;
    }
    let arr = [0, 1];
    for (let i = 2; i <= n; i++) {
        arr[i] = arr[i - 1] + arr[i - 2];
    }
    return arr[n];
};

19、查找对象属性

 const obj = {
    a: {
        b: {
            c: 1,
        },
        d: 2,
    },
};

const path = 'a,d';

const fn = (obj, path) => {
    let res = obj;
    const arr = path.split(',');
    let i = 0;

    while (i < arr.length) {
        const key = arr[i];
        res = res[key];
        i++;
    }

    return res;
};

console.log(fn(obj, path));   

20、多个函数串行执行

const fns = [() => {}, () => {}, () => {}];
const fn = async (arr, params) => {
    let res = params;

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

21、二分法取数

const arr = [1, 2, 3, 4, 5, 6, 7];

const fn = (target) => {
    let start = 0,
        end = arr.length - 1;

    while (start <= end) {
        let mindInd = Math.floor((end + start) / 2);
        let minVal = arr[mindInd];
        if (target < minVal) {
            end = mindInd;
        } else if (target > minVal) {
            start = mindInd;
        } else {
            return mindInd;
        }
    }
};

console.log(fn(2));

22、苛里化

题目一
const sum = (a, b, c) => {
    return a + b + c;
};
const aaa = fn(sum);
const res = aaa(1, 2, 3);
const res1 = aaa(1, 2)(3);
const res2 = aaa(1)(4, 3);

// 实现fn函数
function fn(sum) {
    return function (...args) {
        if (args.length >= sum.length) {
            // 如果参数数量足够,直接执行 sum 函数
            return sum(...args);
        } else {
            // 否则返回一个新的函数,等待更多的参数
            return function (...nextArgs) {
                return fn(sum)(...args, ...nextArgs);
            };
        }
    };
}


题目二
// sum(1, 2, 3).sumOf(); //6
// sum(2, 3)(2).sumOf(); //7
// sum(1)(2)(3)(4).sumOf(); //10
// sum(2)(4, 1)(2).sumOf(); //9

// 实现sum函数
const sum = (...params)=>{
    const fn = (...args)=>{
        return sum(...params, ...args)
    }
    fn.sumOf = ()=>reduce((a,b)=>a+b,0)
    return fn;
}

23、括号匹配判断

function isParenthesesMatched(str) {
    const stack = [];
    for (let i = 0; i < str.length; i++) {
        const c = str[i];
        if (c === '(' || c === '{' || c === '[') {
            stack.push(c);
        } else if (c === ')' || c === '}' || c === ']') {
            const top = stack[stack.length - 1];
            if ((top === '(' && c === ')') || (top === '{' && c === '}') || (top === '[' && c === ']')) {
                stack.pop();
            } else {
                return false;
            }
        }
    }
    return stack.length === 0;
}

console.log(isParenthesesMatched('{}[]()[}'));

24、十进制二进制转换

//思路:除2取余,将余数拼接在结果字符串的开头,然后商除以2再取余,重复此过程,直到商为0
// 十进制转二进制

function toBinary(num) {
    if (num === 0) {
        return '0';
    }
    let result = '';
    while (num > 0) {
        result = (num % 2) + result;
        num = Math.floor(num / 2);
    }
    return result;
}

console.log(toBinary(10));


//思路:从高位开始,每次取二进制数末尾的数,然后乘以2的幂次方,幂次从后往前递增,并求和

// 二进制转十进制
function toDecimal(binary) {
    let result = 0;
    let str = `${binary}`;
    for (let i = str.length - 1; i >= 0; i--) {
        result += parseInt(str[i]) * Math.pow(2, str.length - 1 - i);
    }
    console.log('>>>', result);
    return result;
}

25、数组拉平

var arr = [1, { a: 2 }, [3, [4, 5]]];

function flatDeep(arr) {
    let carr = [];

    const loop = (arr) => {
        arr.forEach((ele) => {
            if (Array.isArray(ele)) {
                loop(ele);
            } else {
                carr.push(ele);
            }
        });
    };

    loop(arr);
    console.log(&#34;carr&#34;, carr);
    return carr;
}

const newArr = flatDeep(arr); // [1, {a: 2}, 3, 4, 5]

26、找数组最短组合值

// 找出数组中数值的加和大于等于目标值的连续的最小数组长度

const s = 7,
nums = [2, 3, 1, 4, 1, 3];

//写个函数输出3,因为[3,1,4]是最短数组组合
const fn = (s,nums)=>{
  let num = nums.length
  let tempArr = []
  let startInd = 0;
  const loop = (ind = 0) => {
    for(let i = ind; i < nums.length; i++){
      tempArr.push(nums[i])
      const res = tempArr.reduce((a,b)=>a+b)
      if(res>s){
        console.log('tempArr>>>',tempArr)
        num = Math.min(num,tempArr.length)
        tempArr = []
        loop(startInd++)
      }
    }
  }
  loop(startInd)
  return num
}

fn(s,nums)

27、找数组最贴近入参的值

const arr = [1, 9, 3, 33, 50, 86, 70];

//比如传入10,返回9
//传入60,返回70(偏大的值)

const fn = (arr, n) => {
    const newArr = arr.map((i) => Math.abs(i - n));
    const num = Math.min(...newArr);
    
    let indArr = [];
    newArr.forEach((i, ind) => {
        if (i === num) {
            indArr.push(ind);
        }
    });

    const resArr = indArr.map((i) => arr[i]);
    return Math.max(...resArr);
};

console.log(fn(arr, 60));

28、重复请求一个接口,有一次成功就返回

// 方法一
const reruest = (url,maxCount = 3) => {
   return fetch(url).catch((err) => 
       maxCount <= 0 ? Promise.reject(err) : reruest(url, maxCount--)
   )
}

// 方法二
const reTry = (url) => {
      return new Promise((resolve, reject) => {
          let count = 0;
          const request = () => {
              axios.get(url).then(resolve).catch(err => {
                  count++;
                  if (count < 3) {
                      request();
                  } else {
                      reject(err);
                  }
              })
          };
      });
};

29、任务并发控制

// 已知如下代码 实现SuperTask
function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 创建一个超时任务类
const superTask = new SuperTask()
function addTask(time,name){
    superTask.add(()=>timeout(time)).then(()=>{
        console.log('任务' + name + '执行完成')
    })
}

addTask(10000,'任务1') // 10000毫秒后输出 '任务1执行完成'
addTask(5000,'任务2') // 5000毫秒后输出 '任务2执行完成'
addTask(3000,'任务3') // 3000毫秒后输出 '任务3执行完成'
addTask(4000,'任务4') // 12000毫秒后输出 '任务4执行完成'
addTask(5000,'任务5') // 15000毫秒后输出 '任务5执行完成'
  
// 从打印可以看出,任务并发数是2
class SuperTask {
    constructor(limit = 2) {
        this.limit = limit; // 并发任务数
        this.queue = [];  // 任务队列
        this.workingCount = 0; // 正在处理的任务数
    }
    add(task){
        return new Promise((resolve, reject) => {
            this.queue.push({ task, resolve, reject });
            this.run();
        });
    }
    run(){
        while(this.queue.length && this.workingCount < this.limit){
            const { task, resolve, reject } = this.queue.shift();
            this.workingCount++;
            task().then(resolve, reject).finally(() => {
                this.workingCount--;
                this.run();
            });
        }
    }
}

30、树转数组

如下代码
const tree = [    {        value: '1',        label: '1',        children: [            {                value: '1-1',                label: '1-1',                children: [                    {                        value: '1-1-1',                        label: '1-1-1'                    },                    {                        value: '1-1-2',                        label: '1-1-2'                    }                ]
            }
        ]
    },
    {
        value: '2',
        label: '2',
        children: [
            {
                value: '2-1',
                label: '2-1'
            },
            {
                value: '2-2',
                label: '2-2'
            }
        ]
    }
]

const arr = treeToArr(tree);
输出 [  [ '1', '1-1', '1-1-1' ],
  [ '1', '1-1', '1-1-2' ],
  [ '2', '2-1' ],
  [ '2', '2-2' ]
]

const treeToArr = (tree)=>{
    const arr = [];
    const loop = (tree, path=[])=>{
        tree.forEach(i=>{
            const tempPath = [...path, i.value]
            if(i.children?.length){
                loop(i.children, tempPath)
            }else{
                arr.push(tempPath)
            }
        })
    }
    loop(tree)
    return arr;
}

31、多任务开始暂停操作

// 有俩按钮,支持任务的开始和暂停,任务执行完返回所有任务的执行结果
开始
暂停

    const runTasks = (...tasks)=>{
        let isRunning = false
        const res = [] //结果
        let index = 0
        const start = () => {
            return new Promise(async (resolve)=>{
                if(isRunning){
                    return
                }
                isRunning = true
                while (index < tasks.length) {
                    const ele = await tasks[index]();
                    res.push(ele)
                    index++
                    if(!isRunning){
                        return
                    }
                }
                isRunning = false
                return resolve(res)
            })
        }
        const stop = () => {
            isRunning = false
        }
        return {
            start,
            stop
        }
    }
    const arr = []
    for(let i=1;i{
            console.log(`任务${i}开始执行`)
            return new Promise((resolve)=>{
                setTimeout(()=>{
                    resolve(i)
                    console.log(`任务${i}执行结束`)
                }, 3000)
            })
        })
    }
    const {start,stop} = runTasks(...arr)
    const startEvent = async () => {
        console.log('点击了开始按钮')
        const data = await start()
        console.log('data==>', data)
    }

    const stopEvent = () => {
        stop()
    }

32、二叉树遍历

const treeNode = {
  val: 1,
  left: {
    val: 2,
    left: {
      val: 4,
      left: null,
      right: null
    },
    right: {
      val: 5,
      left: null,
      right: null
    }
  },
  right: {
    val: 3,
    left: {
      val: 6,
      left: null,
      right: null
    },
    right: {
      val: 7,
      left: null,
      right: null
    }
  }
}

const getTreeArr = (root) => {
  const arr = []
  const _fn = (root)=>{
    if(!root) return
    arr.push(root.val)
    _fn(root.left)
    _fn(root.right)
  }
  _fn(root)
  return arr
}

const a = getTreeArr(treeNode)
console.log('7890>>>',a)