前端常用工具函数🚀

346 阅读6分钟

防抖

/**
 * 防抖
 *
 * @param {func}-业务函数
 * @param {delay}-时间间隔
 * @param {previousTime}-上一次执行函数的时间戳
 * @param {timerId}-定时器
 */
 function debounce(func, delay) {
  let timerId;
  return function (...args) {
    clearTimeout(timerId);
    timerId = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}
// 示例
function saveData() {
  // 这里是保存数据的逻辑
  console.log('保存数据');
}
const debouncedSaveData = debounce(saveData, 1000);
// 当调用 debouncedSaveData 函数时,saveData 函数将在延迟 1000 毫秒后执行
debouncedSaveData();

节流

/**
 * 节流
 *
 * @param {func}-业务函数
 * @param {delay}-时间间隔毫秒
 * @param {previousTime}-上一次执行函数的时间戳
 * @param {timer}-定时器
 * @param {throttledFunc}-返回的函数结果
 */
function throttle(func, delay) {
  let previousTime = 0;
  let timer;
  return function throttledFunc() {
    const currentTime = Date.now();
    //在`throttledFunc`函数内部,比较当前时间戳和`previousTime`的差值,判断是否满足节流的时间间隔。
    if (currentTime - previousTime >= delay) {
      func.apply(this, arguments);
      previousTime = currentTime;
    } else {
    //如果时间间隔不满足条件,清除之前的定时器(如果存在),并创建一个新的定时器,在延迟时间后调用`func`函数,并更新`previousTime`为当前时间戳。
      clearTimeout(timer);
      timer = setTimeout(() => {
        func.apply(this, arguments);
        previousTime = Date.now();
      }, delay);
    }
  };
}
//示例
function doSomething() {
  console.log('Doing something...');
}
const throttledFunc = throttle(doSomething, 1000);
throttledFunc(); // 第一次调用,立即执行
throttledFunc(); // 在1000ms内再次调用,不执行
setTimeout(throttledFunc, 2000); // 在2000ms后调用,执行

深拷贝

/**
 * 深拷贝函数
 *
 * @param {obj}-原始值
 */
function deepCopy(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  
  let copy;
  if (Array.isArray(obj)) {
    copy = [];
    for (let i = 0; i < obj.length; i++) {
      copy[i] = deepCopy(obj[i]);
    }
  } else {
    copy = {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        copy[key] = deepCopy(obj[key]);
      }
    }
  }
  
  return copy;
}
const deepCopy = deepCopy(originalObject);// 拷贝后的对象

一维数组对象的常用操作

根据某个key值是判断一维数组是否有重复项

/**
 *
 * @param {Array}-一维数组对象
 * @param {String}-一维数组对象中的某个键
 * @return {Boolean}-true为复核条件,false为不符合条件
 */
 // methods1
function hasRepeatOfArr1(arr, key) {
  const result = []
  arr.forEach((e) => {
    result.push(e[key])
  })
  return new Set(result).size === 1
}
 // methods2
function hasRepeatOfArr2(arr, key) { 
   return arr.some((item, index) => {
     return arr.findIndex((e, i) => e[key] === item[key] && i !== index) !== -1;
    });
  }

根据某些key值对数据进行过滤并且可以对重复的数据进行操作

/**
 * 示例:一维数组arr根据id和name判断是否有重复的,有重复的项只保留一个且age相加
 *
 * @param {Array}-一维数组对象
 * @param {property}-属性对象
 * @return {result}-结果数组对象
 */
// 定义一个函数,接受一个数组和一个属性对象作为参数
function filterAndDoSomething(Array, property) {
  // 使用 reduce 方法对数组进行累加操作,初始值为一个空对象 {}
  const result = Array.reduce((acc, obj) => {
    let key = '';
    // 遍历属性对象中的每个属性
    for (const prop in property) {
      // 将属性的值拼接到键中
      key += obj[property[prop]] + '-';
    }
    // 去掉键末尾的连字符
    key = key.slice(0, -1);
    // 检查累加结果对象中是否已经存在该键
    if (acc[key]) {
      // 如果已经存在,则将当前对象的年龄累加到已存在对象的年龄上
      acc[key].age += obj.age;
    } else {
      // 如果不存在,则将当前对象复制到累加结果对象中
      acc[key] = { ...obj };
    }
    return acc;
  }, {});
  // 返回累加结果对象的值作为最终结果
  return Object.values(result);
}
const arr = [
  { id: 1, name: 'Alice', age: 20 },
  { id: 2, name: 'Bob', age: 30 },
  { id: 1, name: 'Alice', age: 25 },
  { id: 4, name: 'Charlie', age: 40 },
  { id: 1, name: 'Alice', age: 35 },
  { id: 1, name: 'Bob', age: 45 }
];
// 结果
console.log(filterAndDoSomething(arr, { id: 'id', name: 'name' }));
//输出id且name都一样且对应age相加的数组  
[
  { id: 1, name: 'Alice', age: 80 },
  { id: 2, name: 'Bob', age: 30 },
  { id: 4, name: 'Charlie', age: 40 },
  { id: 1, name: 'Bob', age: 45 }
]

筛选出两个数组对象中不同的元素(一维数组)

/**
 * 筛选出两个数组对象中不同的元素
 *
 * @param {arr1}-需要对比的数组对象1
 * @param {arr2}-需要对比的数组对象2
 * @param {diffElements}-返回的结果包含了两个数组对象中不同的元素。
 */
function findDifferentElements(arr1, arr2, key) {
  const set1 = new Set(arr1.map(item => item[key]));
  const set2 = new Set(arr2.map(item => item[key]));
  const diffElements = [];
  for (const item of arr1) {
    if (!set2.has(item[key])) {
      diffElements.push(item);
    }
  }
  for (const item of arr2) {
    if (!set1.has(item[key])) {
      diffElements.push(item);
    }
  }
  return diffElements;
}
// 示例
const arr1 = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 3, name: 'Tom' }];
const arr2 = [{ id: 2, name: 'Jane' }, { id: 3, name: 'Tom' }, { id: 4, name: 'Alice' }];
const differentElements = findDifferentElements(arr1,arr2,'id');
console.log(differentElements);

数组对象树结构转换的常用操作

树结构转为平铺结构

/**
 * 树结构转为平铺结构(这里并没有根据父子关联来转换)
 *
 * @param {`arr`}-来源数据数组
 * @param {`childKey`}-子项key值可能为child或者children等等
 */
let arrTree = [
   { name: '张三', id: 1, children: [{ name: '张小三', id: 11, children: [{ name: '张小三三', id: 111,children:[] }] }] },
   { name: '李四', id: 2, children: [{ name: '李小四', id: 22, children: [{ name: '李小四四', id: 222,children:[] }] }] },
   { name: '王五', id: 3, children: [{ name: '王小五', id: 33, children: [{ name: '王小五五', id: 333,children:[] }] }] },
   { name: '周六', id: 4, children: [{ name: '周小六', id: 44, children: [] }] },
   { name: '桑七', id: 5, children: [] },
]
// 数组平铺
function treeToRepeat(data,childKey) {
   let result = []
   function repeatArrFun(data, result) {
      if (Array.isArray(data) && data && data.length > 0) {
         for (const item of data) {
            result.push(item)
            if (Array.isArray(item[childKey]) && item[childKey] && item[childKey].length > 0) {
               repeatArrFun(item[childKey], result)
            }
         }
      }
   }
   repeatArrFun(data, result)
   return result
}
console.log(JSON.stringify(treeToRepeat(arrTree,'children')));
// 结果:
[
{"name":"张三","id":1,"children":[{"name":"张小三","id":11,"children":[{"name":"张小三三","id":111,"children":[]}]}]},
{"name":"张小三","id":11,"children":[{"name":"张小三三","id":111,"children":[]}]},
{"name":"张小三三","id":111,"children":[]},
{"name":"李四","id":2,"children":[{"name":"李小四","id":22,"children":[{"name":"李小四四","id":222,"children":[]}]}]},
{"name":"李小四","id":22,"children":[{"name":"李小四四","id":222,"children":[]}]},
{"name":"李小四四","id":222,"children":[]},
{"name":"王五","id":3,"children":[{"name":"王小五","id":33,"children":[{"name":"王小五五","id":333,"children":[]}]}]},
{"name":"王小五","id":33,"children":[{"name":"王小五五","id":333,"children":[]}]},
{"name":"王小五五","id":333,"children":[]},
{"name":"周六","id":4,"children":[{"name":"周小六","id":44,"children":[]}]},
{"name":"周小六","id":44,"children":[]},
{"name":"桑七","id":5,"children":[]}
]

平铺结构转为树结构

// 平铺结构数组(必须保存节点唯一值id和父节点的id唯一值,如果是跟节点唯一值设置为null)
let arrRepeat = [
   { name: '根节点', id: 1, parentId: null },
   { name: '1-1节点', id: 2, parentId: 1 },
   { name: '1-2节点', id: 3, parentId: 1 },
   { name: '1-3节点', id: 4, parentId: 1 },
   { name: '1-4节点', id: 5, parentId: 1 },
   { name: '1-1-1节点', id: 6, parentId: 2 },
   { name: '1-1-2节点', id: 7, parentId: 2 },
   { name: '1-1-2-1节点', id: 8, parentId: 6 },
   { name: '根节点2', id: 99, parentId: null },
]
// 平铺结构转树方法
/**
 * 树结构转为平铺结构
 * @param {`arr`}-来源数据arr
 * @param {`onlyKey`}-每个节点的唯一值
 * @param {`parentKey`}-节点关系值父节点的唯一值
 */
// 平铺结构转树
function arrayToTree(arr, onlyKey, parentKey) {
   if (Array.isArray(arr) && arr.length > 0) {
      let map = {}; // 建立一个映射对象,用于根据id查找数组中的元素  
      let tree = []; // 这个数组将包含转化后的树结构  
      // 将数组中的每个元素添加到map中  
      for (let i = 0; i < arr.length; i++) {
         map[arr[i][onlyKey]] = { ...arr[i], children: [] };
      }
      console.log(map);
      // 构建树结构  
      for (let i = 0; i < arr.length; i++) {
         let node = map[arr[i][onlyKey]];
         console.log(node);
         if (node[parentKey] === null) {
            // 如果是根节点,将其添加到树数组中  
            tree.push(node);
         } else {
            // 如果不是根节点,找到其父节点,并将其添加到父节点的children数组中  
            let parent = map[node[parentKey]];
            if (parent) {
               parent.children.push(node);
            }
         }
      }
      return tree;
   } else {
      return null
   }
}
console.log(JSON.stringify(arrayToTree(arrRepeat,'id','parentId')));
//结果
[
{"name":"根节点","id":1,"parentId":null,
    "children":[{"name":"1-1节点","id":2,"parentId":1,"children":[{"name":"1-1-1节点","id":6,"parentId":2,"children":[{"name":"1-1-2-1节点","id":8,"parentId":6,"children":[]}]},     {"name":"1-1-2节点","id":7,"parentId":2,"children":[]}]},
    {"name":"1-2节点","id":3,"parentId":1,"children":[]},
    {"name":"1-3节点","id":4,"parentId":1,"children":[]},
    {"name":"1-4节点","id":5,"parentId":1,"children":[]}]
},
{"name":"根节点2","id":99,"parentId":null,"children":[]}
]