?0202年了,幾個基礎的手寫函式總得會吧

Ramirez發表於2020-03-20

這幾天看到一個大三大佬面試位元組跳動的蚊子,突然覺得自己太辣雞了···校招的題我一半多都不會啊···趕緊潛下心來學習學習提(an)高(wei)自己,邊翻掘金邊谷歌,簡單實現了幾個常用函式···(借鑑了太多人的文章了··弄不清了··沒法寫出引用了··大佬們請諒解··)

深拷貝 deepClone

function deepClone(target, hash = new WeakMap()) {
  // 不是物件或者是null 直接返回
  if (typeof target !== "object" || target == null) return target;
  // 通過WeakMap判斷是否已有 有則返回物件引用
  if (hash.has(target)) return hash.get(target);
  // 判斷是陣列還是字串
  const result = target instanceof Array ? [] : {};
  // 結果放進WeakMap裡,key是target,值是result
  hash.set(target, result);
  // for in遍歷
  for (const key in target) {
    // 避開原型鏈上的屬性
    if (Object.prototype.hasOwnProperty.apply(target,key)) {
      // 遞迴呼叫
      result[key] = _deepClone(target[key]);
    }
  }
  // 返回結果
  return result;
}
複製程式碼

防抖 debounce

function debounce(handler, wait = 300, immediate = false) {
  // 宣告一個變數timer
  let timer;
  // 判斷引數是否符合預期
  if (typeof handler !== "function") throw new TypeError("The first params shoule be a Function");
  if (typeof wait !== "number") throw new TypeError("The second params shoule be a Number");

  return function() {
    // 快取上下文和引數
    const context = this,
      args = [...arguments];
    // 如果timer存在就清除timer
    timer && clearTimeout(timer);

    if (immediate) {
      // immediate為true且定時器不存在,則設定定時器,並在指定時間後timer設定為null
      const callNow = !timer;
      timer = setTimeout(() => {
        timer = null;
      }, wait);
      // 且立即執行一次handler,通過apply繫結上下文和傳入引數
      callNow && handler.apply(context, args);
    } else {
      // immediate為false則設定定時器
      timer = setTimeout(() => {
        handler.apply(context, args);
      }, wait);
    }
  };
}
複製程式碼

節流 throttle

function throttle(handler, wait = 300) {
  // 宣告一個變數timer
  let timer;
  return function() {
    // timer存在則直接返回怎麼也不幹
    if (timer) return;
    // 快取上下文和引數
    const context = this,
      args = [...arguments];
    // 設定定時器
    timer = setTimeout(() => {
      // 執行handler,通過apply繫結上下文和傳入引數
      handler.apply(context, args);
      // timer設定為null
      timer = null;
    }, wait);
  };
}
複製程式碼

是否是純物件 isPlainObject

function isPlainObject(obj) {
  return Object.prototype.toString.call(obj) === "[object Object]";
}
複製程式碼

深度對比 isEqual

function isEqual(target1, target2) {
  // 直接先對比,相等就返回
  if (target1 === target2) return true;

  const isPlainObject = obj => Object.prototype.toString.call(obj) === "[object Object]";
  //  如果兩者任意一個不是純物件,直接返回對比結果
  if (!isPlainObject(target1) || !isPlainObject(target2)) return target1 === target2;

  // 拿到兩個keys的陣列,長度不一致那肯定不一樣
  const target1Keys = Object.keys(target1);
  const target2Keys = Object.keys(target2);
  if (target1Keys.length !== target2Keys.length) return false;

  // 以target1為基準遍歷,遞迴呼叫isEqual對比每一項,任何一項不一樣直接返回false
  for (const key in target1) {
    if (target1.hasOwnProperty(key)) {
      if (!isEqual(target1[key], target2[key])) return false;
    }
  }
  // 全一樣
  return true;
}
複製程式碼

拍平陣列 flatArray

function flatArray(arr, depth = Infinity) {
  // 不是陣列則報錯
  if (!arr instanceof Array) throw new TypeError("Expect Array");
  // 判斷是否支援ES10的flat方法
  if (Array.prototype.flat) {
    // 支援則直接呼叫
    return arr.flat(depth);
  } else {
    // 看陣列內元素是否都是普通型別
    const isDeep = arr.some(item => Array.isArray(item));
    // 如果都是普通型別則直接返回
    if (!isDeep) return arr;
    // 用陣列concat方法拍平陣列第一層
    const result = [].concat(...arr);
    // 遞迴呼叫,拍平深層陣列
    return flatArray(result);
  }
}
複製程式碼

陣列快排 quickSort

  function quickSort(target) {
    // 不是陣列或者陣列長度小於2,則直接返回
    if (Object.prototype.toString.apply(target) !== '[object Array]' || target.length < 2) return target
    // 拷貝一份陣列
    const _arr = [...target]
    // 找到並取出基準元素
    const pivotItem = _arr.splice(Math.floor(_arr.length / 2), 1)
    // 定義兩個臨時陣列,分別儲存比基準小和比基準大的元素
    const smallerArr = []
    const biggerArr = []
    // 遍歷陣列,將元素分類
    for (let index = 0; index < _arr.length; index++) {
      const element = _arr[index]
      pivotItem > element ? smallerArr.push(element) : biggerArr.push(element)
    }
    // 將兩個臨時陣列遞迴呼叫,並將兩個陣列和基準元素合併起來
    const result = this._quickSort(smallerArr).concat(pivotItem, this._quickSort(biggerArr))
    // 返回新陣列
    return result
  },
複製程式碼

陣列氣泡排序 bubbleSort

  function bubbleSort(target) {
    // 不是陣列或者陣列長度小於2,則直接返回
    if (Object.prototype.toString.apply(target) !== '[object Array]' || target.length < 2) return target
    // 拷貝一份陣列
    const _arr = [...target]
    // 遍歷陣列
    for (let index = 0; index < _arr.length; index++) {
      for (let innerIdx = index + 1; innerIdx < _arr.length; innerIdx++) {
        // 相鄰元素兩兩對比,元素交換,大的元素交換到後面
        if (_arr[index] > _arr[innerIdx]) {
          [_arr[index], _arr[innerIdx]] = [_arr[innerIdx], _arr[index]]
        }
      }
    }
    // 返回新陣列
    return _arr
  }
複製程式碼

相關文章