切換語言為:簡體

前端們必須掌握的 6 個常用且關鍵的工具函式

  • 爱糖宝
  • 2024-07-10
  • 2055
  • 0
  • 0

很多工具函式大家都知道,比如防抖函式,節流函式,深複製函式等,一問都會,一寫就廢,用lodash的各位前端們,是不是基本功都退化了?CV工程師請不要把基本功給弄丟了,下面我來整理一下專案中常用的工具函式,多練練吧,不然面試現場寫不出來多丟人啊!

1.防抖函式

/**
 * 防抖函式,最後一次呼叫,至少等待delay時間才執行,如果在delay時間內再次呼叫就重新計時。
 * @param {*} func  傳入執行函式
 * @param {*} delay 定義間隔時間
 */
export const debounce = (func,delay)=>{
    let timer;
    return function(...args){
      clearTimeout(timer);
      timer = setTimeout(()=>{
        func.apply(this,args);
      },delay)
    }
}

2.節流函式

/**
 * 節流函式,fuc函式離上一次執行間隔delay才執行下一次,如果在delay時間內就重新計時,如果大於delay則更新最後一次的執行時間。
 * @param {*} func 執行函式
 * @param {*} delay 執行時間
 */
export const throttle = (func,delay)=>{
  let timer,last
  return function(...args){
    let  now = + new Date();
    if(last &&  now < last + delay){
      clearTimeout(timer);
      timer = setTimeout(()=>{
        last = now;
        func.apply(this,args);
      },delay)
    }else{
      last = now;
      func.apply(this,args);
    }
  }
}

3.深複製函式

/**
 * 深複製函式
 * @param {*} obj 引數
 */
export const deeClone = (obj) => {
  //不是引用型別就不複製
  if(!(obj instanceof Object)) return obj 
  //如果形參obj是陣列,就建立陣列,如果是物件就建立物件
  let objCopy = obj instanceof Array ? [] : {}  

  for(let key in obj){  
      if(obj instanceof Object){  
          objCopy[key] = deepCopy(obj[key])  
      } else{  
          if(obj.hasOwnProperty(key)){  
              objCopy[key] = obj[key]  
          }
      }  
  }  
  return objCopy  
}

4.物件中刪除某個數,並返回新的物件

 
/**
 * 實現從無限巢狀物件或者陣列中刪除某個數,並返回新的物件
 * @param {*} object 物件
 * @param {*} item 刪除的數
 */
export const deleteItemFromObject = (obj , item)=>{
    if(obj instanceof Object){
      const objCopy = obj instanceof Array ? [] : {}
      for(let i in obj){
        if(obj[i] instanceof Array ){
          objCopy[i] = obj[i].filter( j=> j !== item).map(h => deleteItemFromObject(h, item));
        }else{
          objCopy[i] = deleteItemFromObject(obj[i],item)
        }
      }
      return objCopy
    }else{
      return obj === item ?  null : obj
    }
}

5.請求佇列設定最大請求數

/**
 * 控制併發請求,所有的請求放到請求佇列中,當請求數量大於number時則在佇列中排隊等候,根據http1協議一次性最大請求數為6個
 * @param {*} reqs 請求
 * @param {*} number 請求佇列的數量
 */
export const reqQueue = (reqs ,number)=>{
  reqs = reqs || []
  const requestQueue = (concurrency) => {
    concurrency = concurrency || 6 // 最大併發數
    const queue = [] // 請求池
    let current = 0

    const dequeue = () => {
      while (current < concurrency && queue.length) {
        current++;
        const requestPromiseFactory = queue.shift() // 出列
        requestPromiseFactory()
          .then(() => { // 成功的請求邏輯
          })
          .catch(error => { // 失敗
            console.log(error)
          })
          .finally(() => {
            current--
            dequeue()
          });
      }

    }

    return (requestPromiseFactory) => {
      queue.push(requestPromiseFactory) // 入隊
      dequeue()
    }

  }
  const enqueue = requestQueue(6)

  for (let i = 0; i < reqs.length; i++) {

    enqueue(() => axios.get('/api/test' + i))
  }
}

6.訂閱訊息函式,包括訂閱訊息、釋出訊息和取消訂閱的功能

class EventEmitter {
    constructor() {
        this.events = {};
    }

    // 訂閱訊息
    subscribe(eventName, callback) {
        if (!this.events[eventName]) {
            this.events[eventName] = [];
        }
        this.events[eventName].push(callback);
    }

    // 取消訂閱
    unsubscribe(eventName, callback) {
        if (!this.events[eventName]) {
            return;
        }
        this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
    }

    // 釋出訊息
    publish(eventName, ...args) {
        if (!this.events[eventName]) {
            return;
        }
        this.events[eventName].forEach(callback => callback(...args));
    }
}

// 示例用法
const emitter = new EventEmitter();

// 訂閱訊息
const callback1 = data => console.log('Callback 1:', data);
const callback2 = data => console.log('Callback 2:', data);

emitter.subscribe('message', callback1);
emitter.subscribe('message', callback2);

// 釋出訊息
emitter.publish('message', 'Hello, world!');

// 取消訂閱
emitter.unsubscribe('message', callback2);

// 再次釋出訊息
emitter.publish('message', 'How are you?');

//列印輸出結果:
//Callback 1: Hello, world!
//Callback 2: Hello, world!
//Callback 1: How are you?

實現 get 方法

以下是一個實現 lodash.get 方法的示例:

/**
 * 從物件中獲取巢狀屬性的值,如果屬性不存在,則返回預設值。
 * @param {Object} object - 要查詢的物件
 * @param {Array|string} path - 要獲取的屬性路徑
 * @param {*} [defaultValue] - 如果解析值是 undefined ,這值會被返回
 * @returns {*} - 返回解析的值
 */
function get(object, path, defaultValue) {
  // 如果 path 是字串,使用 . 或 [ ] 分割成陣列
  if (typeof path === 'string') {
    path = path.replace(/\[(\w+)\]/g, '.$1'); // 將 [key] 替換為 .key
    path = path.replace(/^\./, ''); // 去除開頭的 .
    path = path.split('.');
  }

  // 使用陣列路徑進行遍歷
  for (let i = 0; i < path.length; i++) {
    if (object == null) { // 如果物件為 null 或 undefined,返回預設值
      return defaultValue;
    }
    object = object[path[i]];
  }

  return object === undefined ? defaultValue : object;
}

// 示例
const obj = {
  a: {
    b: {
      c: 42,
    },
  },
};

console.log(get(obj, 'a.b.c')); // 輸出: 42
console.log(get(obj, ['a', 'b', 'c'])); // 輸出: 42
console.log(get(obj, 'a.b.c.d', 'default')); // 輸出: default
console.log(get(obj, 'a.b.c', 'default')); // 輸出: 42
console.log(get(obj, 'x.y.z', 'default')); // 輸出: default

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.