Skip to content

工具方法系列

常见方法

debounce 函数防抖

函数防抖

作用: 一个函数在一段时间内多次触发都只执行最后一次
原理: 利用定时器,在函数第一次执行时设定一个定时器,再次调用时如果已经设定过定时器就清空之前的定时器并设定一个新的定时器,当定时器结束后执行传入的回调函数
应用: 搜索输入框获取用户输入的联想结果

实现防抖函数
js
function debounce(fn, wait) {
  // 通过闭包缓存定时器 id
  let timer = null
  return function (...args) {
    // 如果定时器已经存在,清除定时器
    if (timer) {
      clearTimeout(timer)
      timer = null
    }
    // 设定定时器,定时器结束后执行传入的回调函数 fn
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, wait)
  }
}

throttle 函数节流

函数节流

作用: 函数节流指指的是在一段时间内只允许函数执行一次 (例如 3 秒执行一次那么在函数第一次调用后的 3 秒内后面的函数调用将被忽略)
原理: 利用时间戳来判断,记录上次执行的时间戳,在每次触发事件时判断当前时间是否大于上次执行的时间 + 设置的间隔 ,如果是则执行回调并更新上次执行的时间戳
应用: 降低 scroll resize 事件的触发频率

实现节流函数
js
function throttle(fn, wait) {
  // 通过闭包缓存上一次的调用时间 (默认为 0)
  let lastCallTime = 0
  return function () {
    const now = Date.now()
    // 判断当前调用时间和上次调用时间的差值是否大于 wait
    if (now - lastCallTime >= wait) {
      // 更新调用时间
      lastCallTime = now
      // 执行回调函数
      fn.apply(this, arguments)
    }
  }
}

deepClone 深拷贝

深拷贝

原理: 利用 JSON.parse(JSON.stringify(obj)) 实现深拷贝,但是 JSON.stringify 只能处理对象和数组,不能处理函数、undefined、symbol 等类型,所以需要递归处理。 使用 WeakMap 的好处是,WeakMap 存储的 key 必须是对象,并且 key 都是弱引用,便于垃圾回收

应用: 拷贝对象、数组等复杂数据类型,避免引用类型的数据被修改

实现深拷贝
js
/**
 * 深度克隆一个对象或数组
 */
function deepClone(target, hash = new WeakMap()) {
  // 检查目标是否为对象,若不是则直接返回
  if (!isObject(target)) return target
  // 检查hash中是否已存在目标对象,若存在则返回该对象以解决循环引用问题
  if (hash.has(target)) return hash.get(target)
  let obj

  // 处理特殊对象类型
  if (target instanceof Date) {
    obj = new Date(target)
  } else if (target instanceof RegExp) {
    obj = new RegExp(target)
  } else if (target instanceof Map) {
    obj = new Map()
    target.forEach((value, key) => {
      obj.set(key, deepClone(value, hash))
    })
  } else if (target instanceof Set) {
    obj = new Set()
    target.forEach((value) => {
      obj.add(deepClone(value, hash))
    })
  } else {
    // 根据目标对象是数组还是对象,创建相应的空数组或对象
    obj = Array.isArray(target) ? [] : {}
  }
  // 不考虑那么多特殊类型的话上方这一段改成 obj = Array.isArray(target) ? [] : {}

  // 将新创建的对象存入hash,键为目标对象,值为新创建的对象,以处理循环引用
  hash.set(target, obj)
  // 遍历目标对象的所有属性
  for (let key in target) {
    // 确保只处理目标对象自身的属性,而非原型链上的属性
    if (target.hasOwnProperty(key)) {
      // 如果当前属性值是对象,则递归调用deepClone进行深度克隆
      if (isObject(target[key])) {
        obj[key] = deepClone(target[key], hash)
      } else {
        // 如果当前属性值不是对象,则直接赋值
        obj[key] = target[key]
      }
    }
  }
  // 返回克隆后的对象
  return obj
}

const isObject = (target) => {
  return typeof target === 'object' && target !== null
}

const obj = {
  a: 2,
  b: 3,
  c: { d: 4 },
}

obj.d = obj

const newObj = deepClone(obj)
console.log(newObj)

Released under the MIT License.