Skip to content

Js 常用方法

debounce

防抖的意思是,在连续的操作中,无论进行了多长时间,只有某一次的操作后在指定的时间内没有再操作,这一次才被判定有效。

具体场景可以搜索框输入关键字过程中实时 请求服务器匹配搜索结果,如果不进行处理,那么就是输入框内容一直变化,导致一直发送请求。如果进行防抖处理,结果就是当我们输入内容完成后,一定时间(比如 500ms)没有再 输入内容,这时再触发请求。

typescript
let timeout: NodeJS.Timeout | null = null

/**
 * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
export function debounce(func: Function, wait: number = 500, immediate: boolean = false) {
  // 清除定时器
  if (timeout !== null) clearTimeout(timeout)
  // 立即执行,此类情况一般用不到
  if (immediate) {
    let callNow = !timeout
    timeout = setTimeout(() => {
      timeout = null
    }, wait)
    if (callNow) typeof func === 'function' && func()
  } else {
    // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
    timeout = setTimeout(() => {
      typeof func === 'function' && func()
    }, wait)
  }
}

throttle

节流的意思是,规定时间内,只触发一次。比如我们设定 500ms,在这个时间内,无论点击按钮多少次,它都只会触发一次。

具体场景可以是抢购时候,由于有无数人 快速点击按钮,如果每次点击都发送请求,就会给服务器造成巨大的压力,但是我们进行节流后,就会大大减少请求的次数。

typescript
let timer, flag: boolean
/**
 * 节流原理:在一定时间内,只能触发一次
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
export function throttle(func: Function, wait: number = 500, immediate: boolean = true) {
  if (immediate) {
    if (!flag) {
      flag = true
      // 如果是立即执行,则在wait毫秒内开始时执行
      typeof func === 'function' && func()
      timer = setTimeout(() => {
        flag = false
      }, wait)
    }
  } else {
    if (!flag) {
      flag = true
      // 如果是非立即执行,则在wait毫秒内的结束处执行
      timer = setTimeout(() => {
        flag = false
        typeof func === 'function' && func()
      }, wait)
    }
  }
}

deepClone

对象深度克隆

typescript
// 深度克隆
export function deepClone(obj: any) {
  function isObject(value: any): boolean {
    return value !== null && typeof value === 'object'
  }

  function isFn(o: any): o is Function {
    return typeof o === 'function'
  }

  // 对常见的“非”值,直接返回原来值
  if ([null, undefined, NaN, false].includes(obj)) return obj
  if (!isObject(obj) && !isFn(obj)) {
    //原始类型直接返回
    return obj
  }
  const o = Array.isArray(obj) ? ([] as any[]) : ({} as any)

  for (let i in obj) {
    if (obj.hasOwnProperty(i)) {
      o[i] = isObject(obj[i]) ? deepClone(obj[i]) : obj[i]
    }
  }
  return o
}

const a = {
  name: 'a',
}

let b = deepClone(a)

b.name = 'b'

console.log(b) // 结果为 { name: 'b' }
console.log(a) // 结果为 { name: 'a' }

deepMerge

对象深度合并

typescript
/**
 * JS对象深度合并
 * @param target
 * @param source
 * @returns
 */
export function deepMerge(target = {} as any, source = {} as any) {
  function isObject(value: any): boolean {
    return value !== null && typeof value === 'object'
  }

  function deepClone(obj: any) {
    function isObject(value: any): boolean {
      return value !== null && typeof value === 'object'
    }

    function isFn(o: any): o is Function {
      return typeof o === 'function'
    }

    // 对常见的“非”值,直接返回原来值
    if ([null, undefined, NaN, false].includes(obj)) return obj
    if (!isObject(obj) && !isFn(obj)) {
      //原始类型直接返回
      return obj
    }
    const o = Array.isArray(obj) ? ([] as any[]) : ({} as any)

    for (let i in obj) {
      if (obj.hasOwnProperty(i)) {
        o[i] = isObject(obj[i]) ? deepClone(obj[i]) : obj[i]
      }
    }
    return o
  }

  target = deepClone(target)
  if (!isObject(target) || !isObject(source)) return false
  for (var prop in source) {
    if (!source.hasOwnProperty(prop)) continue
    if (prop in target) {
      if (!isObject(target[prop])) {
        target[prop] = source[prop]
      } else {
        if (!isObject(source[prop])) {
          target[prop] = source[prop]
        } else {
          if (target[prop].concat && source[prop].concat) {
            target[prop] = target[prop].concat(source[prop])
          } else {
            target[prop] = deepMerge(target[prop], source[prop])
          }
        }
      }
    } else {
      target[prop] = source[prop]
    }
  }
  return target
}

const a = {
  info: {
    name: 'mary',
  },
}

const b = {
  info: {
    age: '22',
  },
}

const c = deepMerge(a, b)

// c为我们期望的结果
c = {
  info: {
    age: '22',
    name: 'mary',
  },
}

sleep

等待函数

typescript
/**
 * 等待函数
 * @param { number }  ms 延迟秒数
 * @returns
 */
export function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function test() {
  await sleep(3000)
  console.log(1) // 3s后打印
}

test()

timeTaken

计算函数执行时间

typescript
/**
 * 计算函数执行时间
 * @param callback
 * @returns
 */
export const timeTaken = (callback: () => any) => {
  console.time('timeTaken')
  const r = callback()
  console.timeEnd('timeTaken')
  return r
}

timeTaken(() => Math.pow(2, 10)) // 1024, (logged): timeTaken: 0.02099609375ms

memoize

缓存函数

typescript
/**
 * 缓存函数
 * @param fn
 * @returns
 */
export function memoize(fn: Function): Function {
  const cache = Object.create(null)
  return function cachedFn(str: string) {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }
}

memoize()

once

只调用一次的函数

typescript
/**
 * 只调用一次的函数
 * @param fn
 * @returns
 */
export function once(fn: Function): Function {
  let called = false
  return function () {
    if (!called) {
      called = true
      fn.apply(this, arguments)
    }
  }
}

once()

getSize

获取不同类型变量的长度

typescript
/**
 * 获取不同类型变量的长度
 * @param val
 * @returns
 */
export const getSize = (val: any) =>
  Array.isArray(val)
    ? val.length
    : val !== null && typeof val === 'object';
    ? val?.size || val?.length || Object.keys(val)?.length
    : typeof val === 'string'
    ? new Blob([val]).size
    : 0

getSize([1, 2, 3, 4, 5]) // 5
getSize('size') // 4
getSize({ one: 1, two: 2, three: 3 }) // 3

Released under the MIT License.