javascript 常用工具类

我睡着的时候不困唉大约 10 分钟JavaScript前端JavaScript工具类

javascript 常用工具类

数组

判断是否是数组

/**
 * @desc 判断是否是数组
 * @param {Array}} arr 数组
 */
export const arrJudge = (arr) => {
  if (Array.isArray(arr)) {
    return true
  }
}

数组去重

/**
 * @desc 数组去重
 * @param {Array} arr  数组
 */
export const arrRemoveRepeat = (arr) => {
  return Array.from(new Set(arr))
}

数组对象去重

/**
 * @desc 数组对象去重
 * @param {Array} arr1 数组对象  [{ id: 1 }, { id: 2 }, { id: 3 }];
 * @param {Array} arr2 数组对象  [{ id: 3 }, { id: 4 }, { id: 5 }];
 * @retrun {Array} [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 } ]
 */
export const mergeArray = (arr1, arr2) => {
  // 克隆
  const cloneArr1 = arr1.slice(0)
  let v
  for (let i = 0; i < arr2.length; i++) {
    v = arr2[i]
    // 能找到相同 id 属性值的数据则进入判断
    // ~按位非 ~~双非
    if (~cloneArr1.findIndex((el) => el.id === v.id)) {
      continue
    }
    cloneArr1.push(v)
  }
  return cloneArr1
}

数组排序

/**
 * @desc 数组排序
 * @param {Array} arr  数组
 * @param {Boolean} ascendFlag   升序,默认为 true
 */
export const arrOrderAscend = (arr, ascendFlag = true) => {
  return arr.sort((a, b) => {
    return ascendFlag ? a - b : b - a
  })
}

数组最大值

/**
 * @desc 数组最大值
 * @param {Array} arr  数组
 */
export const arrMax = (arr) => {
  return Math.max(...arr)
}

数组求和

/**
 * @desc 数组求和
 * @param {Array} arr 数组
 */
export const arrSum = (arr) => {
  return arr.reduce((prev, cur) => {
    return prev + cur
  }, 0)
}

数组对象求和

/**
 * @desc 数组对象求和
 * @param {Object} arrObj 数组对象
 * @param {String} key 数组对应的 key 值
 */
// eslint-disable-next-line no-unused-vars
export const arrObjSum = (obj, key) => {
  // eslint-disable-next-line no-undef
  return arrObj.reduce((prev, cur) => prev + cur.key, 0)
}

数组合并,目前合并一维

/**
 * @desc 数组合并,目前合并一维
 * @param {Array} arrOne 数组
 * @param {Array} arrTwo 数组
 */
export const arrConcat = (arrOne, arrTwo) => {
  return [...arrOne, ...arrTwo]
}

数组是否包含某值

/**
 * @desc 数组是否包含某值
 * @param {Array} arr 数组
 * @param {}  value 值,目前只支持 String,Number,Boolean
 */
export const arrIncludeValue = (arr, value) => {
  return arr.includes(value)
}

数组并集,只支持一维数组

/**
 * @desc 数组并集,只支持一维数组
 * @param {Array} arrOne
 * @param {Array} arrTwo
 */
export const arrAndSet = (arrOne, arrTwo) => {
  return arrOne.concat(arrTwo.filter((v) => !arrOne.includes(v)))
}

数组交集,只支持一维数组

/**
 * @desc 数组交集,只支持一维数组
 * @param {Array} arrOne
 * @param {Array} arrTwo
 */
export const arrIntersection = (arrOne, arrTwo) => {
  return arrOne.filter((v) => arrTwo.includes(v))
}

数组差集,只支持一维数组

/**
 * @desc 数组差集,只支持一维数组
 * @param {Array} arrOne
 * @param {Array} arrTwo
 * eg: [1, 2, 3] [2, 4, 5] 差集为[1,3,4,5]
 */
export const arrDifference = (arrOne, arrTwo) => {
  return arrOne
    .concat(arrTwo)
    .filter((v) => !arrOne.includes(v) || !arrTwo.includes(v))
}

两个数组合并成一个对象数组,考虑到复杂度,所以目前支持两个一维数组

/**
 * @desc 两个数组合并成一个对象数组,考虑到复杂度,所以目前支持两个一维数组
 * @param {Array} arrOne
 * @param {Array} arrTwo
 * @param {oneKey} oneKey 选填,如果两个都未传,直接以 arrOne 的值作为 key,arrTwo 作为 value
 * @param {twoKey} twoKey
 */
export const arrTwoToArrObj = (arrOne, arrTwo, oneKey, twoKey) => {
  if (!oneKey && !twoKey) {
    return arrOne.map((oneKey, i) => ({ [oneKey]: arrTwo[i] }))
  } else {
    return arrOne.map((oneKey, i) => ({ oneKey, twoKey: arrTwo[i] }))
  }
}

将对象转化为对象数组

/**
 * @desc 将对象转化为对象数组
 * @param {Object} objData
 */
export const objToArr = (objData) => {
  var arr = []
  for (let i in objData) {
    let o = {}
    // eslint-disable-next-line no-undef
    o[i] = obj[i] //即添加了key值也赋了value值 o[i] 相当于o.name 此时i为变量
    arr.push(o)
  }
  return arr
}

多数组相加

/**
 * @desc 多数组相加
 * @param {arr} arr 二维数组
 * [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 4, 5, 6 ] ]
 */
export const arrTotalArray = (arr) => {
  let result = []
  for (let i = 0; i < arr.length; i++) {
    arr[i].forEach((value, index) => {
      if (result[index] == null || result[index] == '') {
        result[index] = 0
      }
      result[index] += parseInt(value)
    })
  }
  return result //[ 9, 12, 15 ]
}

优化高频率执行代码

节流

/**
 * @desc 节流
 * @param {*} func 执行函数
 * @param {*} delay 节流时间,毫秒
 */
export const throttle = function (func, delay) {
  let timer = null
  return function () {
    if (!timer) {
      timer = setTimeout(() => {
        func.apply(this, arguments)
        // 或者直接 func()
        timer = null
      }, delay)
    }
  }
}

防抖

/**
 * @desc 防抖
 * @param {*} fn 执行函数
 * @param {*} wait 防抖时间,毫秒
 */
export const debounce = function (fn, wait) {
  let timeout = null
  return function () {
    if (timeout !== null) clearTimeout(timeout) // 如果多次触发将上次记录延迟清除掉
    timeout = setTimeout(() => {
      fn.apply(this, arguments)
      // 或者直接 fn()
      timeout = null
    }, wait)
  }
}

URL

获取 url 后面通过?传参的参数

/**
 * @desc 获取 url 后面通过?传参的参数
 * @param {String} name
 */
export function getQueryString(name) {
  const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
  const url = window.location.href
  const search = url.substring(url.lastIndexOf('?') + 1)
  const r = search.match(reg)
  if (r != null) return unescape(r[2])
  return null
}

url 参数转对象

/**
 * @desc   url参数转对象
 * @param  {String} url  default: window.location.href
 * @return {Object}
 */
export function parseQueryString(url) {
  url = !url ? window.location.href : url
  if (url.indexOf('?') === -1) {
    return {}
  }
  var search =
    url[0] === '?' ? url.substr(1) : url.substring(url.lastIndexOf('?') + 1)
  if (search === '') {
    return {}
  }
  search = search.split('&')
  var query = {}
  for (var i = 0; i < search.length; i++) {
    var pair = search[i].split('=')
    query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '')
  }
  return query
}

正则

判断是否是数字

/**
 * @desc 判断是否是数字
 * @param {Number} data
 */
export const checkNum = (data) => {
  const reg = /^\d{1,}$/g
  if (reg.test(data)) return true
}

判断是否是字母

/**
 * @desc 判断是否是字母
 * @param {Number} data
 */
export const checkLetter = (data) => {
  const reg = /^[a-zA-Z]+$/g
  if (reg.test(data)) return true
}

判断是否全部是小写字母

/**
 * @desc 判断是否全部是小写字母
 * @param {Number} data
 */
export const checkLowercaseLetter = (data) => {
  const reg = /^[a-z]+$/g
  if (reg.test(data)) return true
}

判断是否是大写字母

/**
 * @desc  判断是否是大写字母
 * @param {Number} data
 */
export const checkCapitalLetter = (data) => {
  const reg = /^[A-Z]+$/g
  if (reg.test(data)) return true
}

判断是否是字母或数字

/**
 * @desc 判断是否是字母或数字
 * @param {Number || String} data  字符或数字
 */
export const checkNumOrLetter = (data) => {
  const reg = /^[0-9a-zA-Z]*$/g
  if (reg.test(data)) return true
}

判断是否是中文

/**
 * @desc 判断是否是中文
 * @param {String} data  中文
 */
export const checkChinese = (data) => {
  const reg = /^[\u4E00-\u9FA5]+$/g
  if (reg.test(data)) return true
}

判断是否是中文,数字或字母

/**
 * @desc 判断是否是中文,数字或字母
 * @param {String} data  中文,数字或字母
 */
export const checkChineseNumberLettter = (data) => {
  const reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/g
  if (reg.test(data)) return true
}

判断是否是邮箱地址

/**
 * @desc 判断是否是邮箱地址
 * @param {String} data
 */
export const checkEmail = (data) => {
  const reg =
    /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/g
  if (reg.test(data)) return true
}

判断是否是手机号

/**
 * @desc 判断是否是手机号,只要是13,14,15,16,17,18,19开头即可
 * @param {String} data
 */
export const checkTelphone = (data) => {
  const reg = /^((\+|00)86)?1[3-9]\d{9}$/g
  if (reg.test(data)) return true
}

判断是否是正确的网址

/**
 * @desc 判断是否是正确的网址
 * @param {String} url 网址
 */
export const checkUrl = (url) => {
  const a = document.createElement('a')
  a.href = url
  return (
    [
      /^(http|https):$/.test(a.protocol),
      a.host,
      a.pathname !== url,
      a.pathname !== `/${url}`
    ].find((x) => !x) === undefined
  )
}

判断是否为 16 进制颜色

/**
 * @desc 判断是否为16进制颜色,rgb 或 rgba
 * @param  {String}  str
 * @return {Boolean}
 */
export const isColor = (str) => {
  return /^(#([0-9a-fA-F]{3}){1,2}|[rR][gG][Bb](\((\s*(2[0-4]\d|25[0-5]|[01]?\d{1,2})\s*,){2}\s*(2[0-4]\d|25[0-5]|[01]?\d{1,2})\s*\)|[Aa]\((\s*(2[0-4]\d|25[0-5]|[01]?\d{1,2})\s*,){3}\s*([01]|0\.\d+)\s*\)))$/.test(
    str
  )
}

判断是否为身份证号

/**
 * @desc  判断是否为身份证号
 * @param  {String|Number} str
 * @return {Boolean}
 */
export const isIdCard = (str) => {
  return /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/.test(
    str
  )
}

客户端环境检测

判断是浏览器内核

/**
 * @desc 判断是浏览器内核
 */
export const checkBrowser = () => {
  const u = navigator.userAgent
  const obj = {
    trident: u.indexOf('Trident') > -1, //IE内核
    presto: u.indexOf('Presto') > -1, //opera内核
    webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
    gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1 //火狐内核
  }
  return Object.keys(obj)[Object.values(obj).indexOf(true)]
}

判断是终端类型,值有 ios,android,iPad

/**
 * @desc 判断是终端类型,值有ios,android,iPad
 */
export const checkIosAndroidIpad = () => {
  const u = navigator.userAgent
  const obj = {
    ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
    android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
    iPad: u.indexOf('iPad') > -1 //是否iPad
  }
  return Object.keys(obj)[Object.values(obj).indexOf(true)]
}

判断是否是微信,qq 或 uc

/**
 * @desc 判断是否是微信,qq 或 uc
 */
export const checkWeixinQqUc = () => {
  const u = navigator.userAgent
  const obj = {
    weixin: u.indexOf('MicroMessenger') > -1, //是否微信
    qq: u.match(/QQ/i) == 'qq' && !u.indexOf('MQQBrowser') > -1, //是否QQ
    uc: u.indexOf('UCBrowser') > -1
  }
  return Object.keys(obj)[Object.values(obj).indexOf(true)]
}

检查是否是 IphoneX

/**
 * @desc 检查是否是 IphoneX
 */
export const checkIsIphoneX = () => {
  const u = navigator.userAgent
  const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
  if (isIOS && screen.height >= 812) {
    return true
  }
}

判断浏*览器是否支持 webP 格式图片

/**
 * @desc 判断浏*览器是否支持webP格式图片
 * @return {Boolean}
 */
export const isSupportWebP = () => {
  return (
    !![].map &&
    document
      .createElement('canvas')
      .toDataURL('image/webp')
      .indexOf('data:image/webp') == 0
  )
}

时间/日期

获取年份

/**
 * @desc 获取年份
 */
export const getYear = () => {
  return new Date().getFullYear()
}

获取当前月份

/**
 * @desc 获取当前月份
 * @param {Boolean} fillFlag 布尔值,是否补 0,默认为 true
 */
export const getMonth = (fillFlag = true) => {
  const mon = new Date().getMonth() + 1
  const monRe = mon
  if (fillFlag) mon < 10 ? `0${mon}` : mon
  return monRe
}

获取日

/**
 * @desc 获取日
 * @param {Boolean} fillFlag 布尔值,是否补 0
 */
export const getDay = (fillFlag = true) => {
  const day = new Date().getDate()
  const dayRe = day
  if (fillFlag) day < 10 ? `0${day}` : day
  return dayRe
}

获取星期几

/**
 * @desc 获取星期几
 */
export const getWhatDay = () => {
  return new Date().getDay() ? new Date().getDay() : 7
}

获取当前月天数

/**
 * @desc 获取当前月天数
 * @param {String} year 年份
 * @param {String} month 月份
 */
export const getMonthNum = (year, month) => {
  var d = new Date(year, month, 0)
  return d.getDate()
}

获取当前时间 yyyy-mm-dd,hh:mm:ss

/**
 * @desc 获取当前时间 yyyy-mm-dd,hh:mm:ss
 */
export const getYyMmDdHhMmSs = () => {
  const date = new Date()
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hours = date.getHours()
  const minu = date.getMinutes()
  const second = date.getSeconds()
  const arr = [month, day, hours, minu, second]
  arr.forEach((item) => {
    item < 10 ? '0' + item : item
  })
  return (
    year +
    '-' +
    arr[0] +
    '-' +
    arr[1] +
    ' ' +
    arr[2] +
    ':' +
    arr[3] +
    ':' +
    arr[4]
  )
}

时间戳转化为年月日

function getzf(time) {
  return +time < 10 ? `0${time}` : time
}

/**
 * @desc 时间戳转化为年月日
 * @param times 时间戳
 * @param ymd 格式类型(yyyy-mm-dd,yyyy/mm/dd)
 * @param hms 可选,格式类型(hh,hh:mm,hh:mm:ss)
 * @returns {年月日}
 */
export const timesToYyMmDd = (times, ymd, hms) => {
  const oDate = new Date(times)
  const oYear = oDate.getFullYear()
  const oMonth = oDate.getMonth() + 1
  const oDay = oDate.getDate()
  const oHour = oDate.getHours()
  const oMin = oDate.getMinutes()
  const oSec = oDate.getSeconds()
  let oTime // 最后拼接时间
  // 年月日格式
  switch (ymd) {
    case 'yyyy-mm-dd':
      oTime = oYear + '-' + getzf(oMonth) + '-' + getzf(oDay)
      break
    case 'yyyy/mm/dd':
      oTime = oYear + '/' + getzf(oMonth) + '/' + getzf(oDay)
      break
  }
  // 时分秒格式
  switch (hms) {
    case 'hh':
      oTime = ' ' + oTime + getzf(oHour)
      break
    case 'hh:mm':
      oTime = oTime + getzf(oHour) + ':' + getzf(oMin)
      break
    case 'hh:mm:ss':
      oTime = oTime + getzf(oHour) + ':' + getzf(oMin) + ':' + getzf(oSec)
      break
  }
  return oTime
}

将年月日转化成时间戳

/**
 * @desc 将年月日转化成时间戳
 * @param {String} time yyyy/mm/dd 或yyyy-mm-dd 或yyyy-mm-dd hh:mm 或yyyy-mm-dd hh:mm:ss
 */
export const YyMmDdToTimes = (time) => {
  return new Date(time.replace(/-/g, '/')).getTime()
}

比较时间 1 小于时间 2

/**
 *  @desc 比较时间 1 小于时间 2
 * @param {String} timeOne  时间 1
 * @param {String} timeTwo  时间 2
 */
export const compareTimeOneLessTwo = (timeOne, timeTwo) => {
  // 判断 timeOne 和 timeTwo 是否
  return (
    new Date(timeOne.replace(/-/g, '/')).getTime() <
    new Date(timeTwo.replace(/-/g, '/')).getTime()
  )
}

时间戳转化为年月日

/**
 * @desc 时间戳转化为年月日
 * @param {Date} startTime
 * @return {String}
 */
export const formatPassTime = (startTime) => {
  const currentTime = Date.parse(new Date()),
    time = currentTime - startTime,
    day = parseInt(time / (1000 * 60 * 60 * 24)),
    hour = parseInt(time / (1000 * 60 * 60)),
    min = parseInt(time / (1000 * 60)),
    month = parseInt(day / 30),
    year = parseInt(month / 12)
  if (year) return year + '年前'
  if (month) return month + '个月前'
  if (day) return day + '天前'
  if (hour) return hour + '小时前'
  if (min) return min + '分钟前'
  else return '刚刚'
}

格式化现在距${endTime}的剩余时间

/**
 * @desc   格式化现在距${endTime}的剩余时间
 * @param  {Date} endTime
 * @return {String}
 */
export const formatRemainTime = (endTime) => {
  var startDate = new Date() //开始时间
  var endDate = new Date(endTime) //结束时间
  var t = endDate.getTime() - startDate.getTime() //时间差
  var d = 0,
    h = 0,
    m = 0,
    s = 0
  if (t >= 0) {
    d = Math.floor(t / 1000 / 3600 / 24)
    h = Math.floor((t / 1000 / 60 / 60) % 24)
    m = Math.floor((t / 1000 / 60) % 60)
    s = Math.floor((t / 1000) % 60)
  }
  return d + '天 ' + h + '小时 ' + m + '分钟 ' + s + '秒'
}

判断是否为同一天

/**
 * @desc   判断是否为同一天
 * @param  {Date} date1
 * @param  {Date} date2 可选/默认值:当天
 * @return {Boolean}
 */
export const isSameDay = (date1, date2) => {
  if (!date2) {
    date2 = new Date()
  }
  var date1_year = date1.getFullYear(),
    date1_month = date1.getMonth() + 1,
    date1_date = date1.getDate()
  var date2_year = date2.getFullYear(),
    date2_month = date2.getMonth() + 1,
    date2_date = date2.getDate()

  return (
    date1_date === date2_date &&
    date1_month === date2_month &&
    date1_year === date2_year
  )
}

计算${startTime - endTime}的剩余时间

/**
 * @desc 计算${startTime - endTime}的剩余时间 ,startTime大于endTime时,均返回0
 * @param { Date | String } startTime
 * @param { Date | String } endTime
 * @returns { Object } { d, h, m, s } 天 时 分 秒
 */
export const timeLeft = (startTime, endTime) => {
  if (!startTime || !endTime) {
    return
  }
  var startDate, endDate
  if (startTime instanceof Date) {
    startDate = startTime
  } else {
    startDate = new Date(startTime.replace(/-/g, '/')) //开始时间
  }
  if (endTime instanceof Date) {
    endDate = endTime
  } else {
    endDate = new Date(endTime.replace(/-/g, '/')) //结束时间
  }
  var t = endDate.getTime() - startDate.getTime()
  var d = 0,
    h = 0,
    m = 0,
    s = 0
  if (t >= 0) {
    d = Math.floor(t / 1000 / 3600 / 24)
    h = Math.floor((t / 1000 / 60 / 60) % 24)
    m = Math.floor((t / 1000 / 60) % 60)
    s = Math.floor((t / 1000) % 60)
  }
  return { d, h, m, s }
}