前端你应该了解常见的算法

628 阅读2分钟
// 防抖
function debounce (fn, time = 1000) {
  let timeId = null;
  return function (...args) {
    if (timeId) clearTimeout(timeId);
    timeId = setTimeout(() => {
     fn.apply(this, args);
     timeId = null;
    })
  }
}

// 节流
function throttle (fn, time = 16.67) {
  const { performance, Date } = window || globalThis;
  const getDate = performance || Date;
  let cacheTime = getDate.now();
  return function (...args) {
    const curTime = getDate.now();
    if (curTime - cacheTime > time) {
      fn.apply(this, args);
      cacheTime = curTime;
    }
  }
}

// 防抖加节流
function douM (fn, debounceTime = 1000, throttleTime = 16.67) {
  const d = debounce(fn, debounceTime);
  const t = throttle(fn, throttleTime);
  return function (...args) {
    d.apply(this, args);
    t.apply(this, args);
  }
}

// 搜索树
function searchToNewTree (arr, value, { label = 'label', children = 'children' }) {
  const newTree = [];
  arr.forEach(item => {
   if (~item[label].indexOf(value)) {
    newTree.push(item);
   } else {
    const child = searchToNewTree(item[children], value, { label, children });
    if (child.length) {
      newTree.push({ ...item, [children]: child });
    }
   }
  });
  return newTree;
}

// 对象深拷贝
function deep (obj, objCache = new WeakMap()) {
  if (obj instanceof Array) {
    const newArray = [];
    for (const item of obj) {
      newArray.push(deep(item, objCache));
    }
    return newArray;
  } else if (obj instanceof Object) {
    let newObj = objCache.get(obj);
    if (newObj) {
      return newObj
    } else {
      newObj = {};
      Reflect.ownKeys(obj).forEach(key => {
        newObj[key] = deep(obj[key], objCache)
      })
      objCache.set(obj, newObj);
      return newObj;
    }  
  } else {
    return obj;
  }
}

// 一维数组转换为树
function arrToTree (arr, { id = 'id', pid = 'pid', children = 'children' }) {
  const newArr = JSON.parse(JSON.stringify(arr));
  const objCache = {};
  newArr.forEach(item => objCache[item[id]] = item)
  const result = newArr.filter(item => !objCache[item[pid]]);
  newArr.forEach(item => {
    const parent = objCache[item[pid]];
    if (parent) {
      if (parent[children]) {
        parent[children].push(item);
      } else {
        parent[children] = [item];
      }
    }
  })
  return result;
}

// 全排列
var _allSort = (function () {
  const result = [];
  function findDiff (temp, nums, length) {
    if (!length) {
      result.push([...temp])
    }
    for (let i = 0; i < length; ++i) {
      temp.push(nums.splice(i, 1)[0])
      findDiff(temp, nums, nums.length);
      nums.splice(i, 0, temp.pop());
    }
  }
  return function (nums) {
    result.length = 0;
    findDiff([], nums, nums.length)
    return [...result];
  }
})()

// 数组扁平化
function flatten (arr, dep = 1) {
  const newArr = [];
  dep-- ? arr.forEach(item => item instanceof Array ? newArr.push(...flatten(item)) : newArr.push(item)) : newArr.push(...arr);
  return newArr;
}


// 深度遍历
function dfs (arr) {
  arr.forEach(item => {
    item.children && dfs(item.children)
  })
}

// 广度遍历
function bfs (arr) {
  const list = [...arr]
  while (list.length) {
    const item = list.shift();
    item.children && list.push(...item.children)
  }
}

// 斐波那契
const fbnq = (function () {
  const cache = [0, 1, 2];
  return function (num) {
    return cache[num] || (cache[num] = arguments.callee(num - 1) + arguments.callee(num - 2))
  }
})()

// 手写Promise
const status = Symbol('status');

class MyPromise {
  [status] = 'pending';
  #value;
  #onFulFillCallbacks = [];
  #onRejectCallbacks = [];
  constructor (fn) {
    const resolve = (value) => {
      if (this[status] === 'pending') {
        this.#value = value;
        this[status] = 'fulfilled';
        this.#onFulFillCallbacks.forEach(fn => fn());
      }
    }
    const reject = (value) => {
      this.#value = value;
      this[status] = 'rejected';
      this.#onRejectCallbacks.forEach(fn => fn());
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err);
    }
  }
  
  static resolve (value) {
    return new MyPromise((res) => res(value))
  }

  then (resolve, reject) {
    const promise = new MyPromise((res, rej) =>  {
      if (this[status] === 'fulfilled') queueMicrotask(() => resolvePromise(promise, resolve(this.#value), res, rej))
      else if (this[status] === 'rejected') queueMicrotask(() => resolvePromise(promise, reject(this.#value), res, rej))
      else if (this[status] === 'pending') {
        this.#onFulFillCallbacks.push(() => queueMicrotask(() => resolvePromise(promise, resolve(this.#value), res, rej)))
        this.#onRejectCallbacks.push(() => queueMicrotask(() => resolvePromise(promise, reject(this.#value), res, rej)))
      }
    })
    return promise;
  }
}

function resolvePromise (promise, value, resolve, reject) {
  try {
    if (value instanceof Promise) {
      promise.then.call(value, res => resolvePromise(promise, res, resolve, reject))
    } else {
      resolve(value);
    }
  } catch (err) {
    reject(err)
  }
}