切换语言为:繁体

前端们必须掌握的 6 个常用且关键的工具函数

  • 爱糖宝
  • 2024-07-10
  • 2056
  • 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.