JS 常用工具函数


前言

本文主要记录一些较为常见且实用的工具函数。

1. 防抖节流

防抖函数的作用是确保在事件触发 n 秒后再执行回调函数,如果在这 n 秒内又触发了事件,则重新计时。

function debounce(func, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

节流函数的作用是确保在短时间内只触发一次事件,如果在这个时间内触发了多次事件,只有一次事件会被执行。

function throttle(func, delay) {
  let last = 0;
  return function(...args) {
    const now = Date.now();
    if (now - last >= delay) {
      func.apply(this, args);
      last = now;
    }
  };
}

2. URL 相关

// 对象转查询(参数)字符串
export const jsonObj2QueryStr = (jsonObj, encode = true) => {
  return Object.keys(jsonObj).map(k => {
    if (encode) return encodeURIComponent(k) + '=' + encodeURIComponent(jsonObj[k])
    return k + '=' + jsonObj[k]
  }).join('&')
}

// 把json对象转换成查询参数添加进URL中
export const addUrlParams = (url, params) => {
  let queryStr = jsonObj2QueryStr(params)
  if (url.indexOf('?') !== -1) {
    return url + '&' + queryStr
  }
  return url + '?' + queryStr
}

// 把 url 参数转换成对象
export const urlParams2Json = (uri) => {
  let jsonObj = {}
  let paramsStr = uri.split('?')[1]
  if (paramsStr) {
    let paramsArr = paramsStr.split('&')
    paramsArr.forEach(item => {
      let key = item.split('=')[0]
      let val = item.split('=')[1] || ''
      jsonObj[key] = val
    })
  }
  return jsonObj
}

3. 金额转换

// 数值/数值字符串转换千分位
function toThousands(value, precision = 2) {
  // 如果输入不是数值或数值字符串,直接返回原值
  if (isNaN(value) || value === null || value === undefined) {
    return value;
  }
  const num = Number(value);
  // 使用 toLocaleString 方法将数值转换为千分位展示的字符串
  const formatted = num.toLocaleString(undefined, {
    minimumFractionDigits: precision,
    maximumFractionDigits: precision
  });
  return formatted;
}

// 千分位字符串转数值
function thousandsToNum(str) {
  // 先去除千分位的逗号
  const numStr = str.replace(/,/g, '');
  // 然后使用 Number 函数将字符串转换为数值
  return Number(numStr);
}

// 金额数值转换成大写金额
export const transMoneyCN = (number) => {
  number = number + ''
  let minus = /^-\.*/.test(number)
  if (minus) {
    number = number.substr(1, number.length - 1)
  }
  let ret = ''
  if (number != '' && number != null && number != '0') {
    let unit = '仟佰拾亿仟佰拾万仟佰拾元角分',
      str = ''
    number += '00'
    let point = number.indexOf('.')
    if (point >= 0) {
      number = number.substring(0, point) + number.substr(point + 1, 2)
    }
    unit = unit.substr(unit.length - number.length)
    for (let i = 0; i < number.length; i++) {
      str +=
        '零壹贰叁肆伍陆柒捌玖'.charAt(number.charAt(i)) + unit.charAt(i)
    }
    ret = str.replace(/零(仟|佰|拾|角)/g, '零')
        .replace(/(零)+/g, '零')
        .replace(/零(万|亿|元)/g, '$1')
        .replace(/(亿)万|(拾)/g, '$1$2')
        .replace(/^元零?|零分/g, '')
        .replace(/元$/g, '元')
    if (point <= -1) {
      ret += '整'
    }
  }
  return minus ? ('负' + ret) : ret
}

4. 深拷贝

// WeakMap 解决循环引用
let map = new WeakMap()
// 深拷贝
export function deepClone(obj) {
  // 区分基本类型和引用类型
  if (obj instanceof Object) {
    // 如果已经存储过这个对象,直接从map获取
    if (map.has(obj)) {
      return map.get(obj)
    }
    let newObj
    // 细分 Object 的常见具体类型 - 函数、正则、Date对象、普通对象(含数组)
    if (obj instanceof Array) {
      newObj = []
    } else if (obj instanceof Function) {
      newObj = function () {
        return obj.apply(this, arguments)
      }
    } else if (obj instanceof RegExp) {
      newObj = new RegExp(obj.source, obj.flags) 
    } else if (obj instanceof Date) {
      newObj = new Date(obj)
    } else {
      newObj = {}
    }
    // 克隆一份对象出来
    let desc = Object.getOwnPropertyDescriptors(obj)
    let clone = Object.create(Object.getPrototypeOf(obj), desc)
    map.set(obj, clone)
    // 处理数组/对象
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        newObj[key] = deepClone(obj[key])
      }
    }
    return newObj
  } else {
    return obj
  }
}

5. Storge/Session/cookie

const isJsonStr = str => {
  try {
    let obj = JSON.parse(str)
    if (obj && typeof obj === 'object') return true
    return false
  } catch (e) {
    return false
  }
}
export const storage = {
  set: (key, val) => {
    if (typeof val === 'object') val = JSON.stringify(val)
    localStorage.setItem(key, val)
  },
  get: key => {
    let r = localStorage.getItem(key)
    if (isJsonStr(r)) return JSON.parse(r)
    return r
  },
  remove: key => {
    localStorage.removeItem(key)
  },
  clear: () => {
    localStorage.clear()
  }
}

export const cookie = {
  set: (key, val, expires = 0) => {
    let cookieStr = ''
    cookieStr += encodeURIComponent(key) + '=' + encodeURIComponent(val)
    if (expires) {
      let d = new Date()
      d.setTime(d.getTime() + (expires * 1000))
      cookieStr += '; expires=' + d.toGMTString()
    }
    cookieStr += '; path=/'
    document.cookie = cookieStr
  },
  get: key => {
    let name = encodeURIComponent(key)
    let reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)')
    let arr = document.cookie.match(reg)
    if (arr) return unescape(arr[2])
    return null
  },
  remove: key => {
    this.set(key, '', -1)
  },
  clear: () => {
    const keys = document.cookie.match(/[^ =;]+(?==)/g)
    if (keys) {
      for (let i = keys.length; i--;) {
        // 清除当前域名下的,例如:a.abc.com
        document.cookie = keys[i] + '=0;path=/;expires=' + new Date(0).toUTCString()
        document.cookie = keys[i] + '=0;path=/;domain=' + document.domain + ';expires=' + new Date(0).toUTCString()
        // 清除一级域名下的或指定的,例如 .abc.com
        document.cookie = keys[i] + '=0;path=/;domain=kevis.com;expires=' + new Date(0).toUTCString()
      }
    }
  }
}

export const session = {
  set: (key, val) => {
    if (typeof val === 'object') val = JSON.stringify(val)
    sessionStorage.setItem(key, val)
  },
  get: key => {
    let r = sessionStorage.getItem(key)
    if (isJsonStr(r)) return JSON.parse(r)
    return r
  },
  remove: key => {
    sessionStorage.removeItem(key)
  },
  clear: () => {
    sessionStorage.clear()
  }
}

6. 文件下载

// 导出文件流下载
export const fileStreamExport = (data, filename, mime) => {
  let blob = new Blob([data], {type: mime || 'application/octet-stream'})
  if (typeof window.navigator.msSaveBlob !== 'undefined') {
    window.navigator.msSaveBlob(blob, filename)
  } else {
    let blobURL = window.URL?.createObjectURL ? window.URL.createObjectURL(blob) : window.webkitURL.createObjectURL(blob)
    downloadFileByURL(blobURL, filename)
  }
}

// 通过URL下载
export const downloadFileByURL = (url, filename) => {
  // 创建a标签实现下载
  const link = document.createElement('a')
  link.style.display = 'none'
  link.href = url
  if (filename) link.setAttribute('download', filename) // 自定义文件名
  if (typeof link.download === 'undefined') {
    link.setAttribute('target', '_blank')
  }
  document.body.appendChild(link)
  link.click()
  // 释放内存
  setTimeout(() => {
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  }, 200)
}

7. 拷贝到剪切板

export const copy2clipboard = (text, el) => {
  if (el) {
    el.value = text
    el.setSelectionRange(0, text.length)
    return document.execCommand('copy')
  }
  let inputEl = document.querySelector('input.disguise-hide')
  if (!inputEl) {
    document.body.insertAdjacentHTML('beforeend', `<input class="disguise-hide" value="${text}">`)
    inputEl = document.body.lastElementChild
  } else {
    inputEl.value = text
  }
  inputEl.focus()
  inputEl.setSelectionRange(0, text.length)
  let val = document.execCommand('copy')
  inputEl.blur()
  return val
}

8. Date 对象转指定格式字符串

function formatDate(date, format = 'yyyy-MM-dd') {
  const map = {
    'M': date.getMonth() + 1,
    'd': date.getDate(),
    'h': date.getHours(),
    'm': date.getMinutes(),
    's': date.getSeconds(),
    'q': Math.floor((date.getMonth() + 3) / 3),
    'S': date.getMilliseconds()
  };

  return format.replace(/([yMdhmsqS])+/g, (all, t) => {
    let v = map[t];
    if (v !== undefined) {
      if (all.length > 1) {
        v = '0' + v;
        v = v.substr(v.length - 2);
      }
      return v;
    } else if (t === 'y') {
      return (date.getFullYear() + '').substr(4 - all.length);
    }
    return all;
  });
}
  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值