JS用法

120 阅读5分钟

1、扁平数组转Tree

方式一

/**
 * @description 扁平数组转Tree(递归)
 * @param {*} arr 数组
 * @returns 
 */
export const getTree1 = (arr = [], pid = 0) => {
  const res = []

  arr.forEach(item => {
    if (pid === item.pid) {
      // 求子孩子
      item['children'] = getTree1(arr, item.id)
      res.push(item)
    }
  })

  return res
}

方式二

/**
 * @description 扁平数组转Tree(map)
 * @param {*} arr 数组 
 */
export const getTree2 = (arr = []) => {
  const res = []
  const map = new Map()

  arr.forEach(item => {
    map.set(item.id, { ...item, children: [] })
  })

  arr.forEach(item => {
    const [parent, self] = [map.get(item.pid), map.get(item.id)]
    parent ? parent.children.push(self) : res.push(self)
  })

  return res
}

2、深拷贝

方式一

/**
 * @description 深拷贝(递归)
 * @param {*} origin 
 * @returns 
 */
export const deepClone1 = (origin = {}) => {
  let target = {}
  for (let prop in origin) {
    if (origin.hasOwnProperty(prop)) {
      if (origin[prop] && typeof origin[prop] === 'object') {
        target[prop] = origin[prop].constructor === Array ? [] : {}
        deepClone1(origin[prop], target[prop])
      } else {
        target[prop] = origin[prop]
      }
    }
  }
  return target
}

方式二

/**
 * @description 深拷贝(JSON方法)
 * @param {*} origin 
 * @returns 
 */
export const deepClone2 = (origin) => {
  return JSON.parse(JSON.stringify(origin))
}

3、数组乱序

/**
 * @description 数组乱序
 * @param {*} arr 
 * @returns 
 */
export const arrOutOfOrder = (arr = []) => {
  return arr.sort(() => Math.random() - 0.5)
}

4、数组去重

/**
 * 数组去重
 * @param {*} arr 
 * @returns 
 */
export const unique = (arr = []) => {
  return [...new Set(arr)]
}

5、获取数组最大值

/**
 * @description 获取数组最大值
 * @param {*} arr 
 * @returns 
 */
export const getMax = (arr = []) => {
  return Math.max(...arr)
}

6、获取数组最小值

/**
 * @description 获取数组最小值
 * @param {*} arr 
 * @returns 
 */
export const getMin = (arr = []) => {
  return Math.min(...arr)
}

7、合并数组或对象

/**
 * @description 合并数组或对象(...扩展运算符)
 */
const mergeArrOrObj = () => {

  // 合并数组(相同元素不会进行覆盖)
  const [arr1, arr2, arr3] = [[1], [2, 3], [3]]
  console.log([...arr1, ...arr2, ...arr3])

  // 合并对象(相同属性,后者覆盖前者)
  const [obj1, obj2, obj3] = [{ name: 'mei' }, { name: 'meibo', age: 23 }, { sex: 'male' }]
  console.log({ ...obj1, ...obj2, ...obj3 })
}

8、过滤数组中的false值

/**
 * @description 过滤数组中的false值(null、undefined、false、''、0)
 * @param {*} arr 
 * @returns 
 */
export const filterF = (arr = []) => {
  return arr.filter(Boolean)
}

9、数组求和

/**
 * @description 数组求和
 * @param {*} arr 
 * @returns 
 */
export const getSumOfArr = (arr = []) => {
  return arr.reduce((preRes, curV) => preRes + curV)
}

10、统计数组中各元素的个数

/**
 * @description 统计数组中各元素的个数
 * @param {*} arr 
 * @returns 
 */
export const getEleNumOfArr = (arr = []) => {
  return arr.reduce((preRes, curV) => {
    preRes[curV] ? preRes[curV]++ : preRes[curV] = 1
    return preRes
  }, {})
}

11、ES6+ 数组方法

/**
 * @description ES6+ 数组方法
 */
const useArrFn = () => {
  const arr = [0, 1, 2]

  // 1、forEach(遍历数组)
  // 参数:cb(遍历项、索引、数组本身)
  arr.forEach((item, index, arr) => {
    console.log(item, index, arr)
  })

  // 2、map(返回经处理后的新数组)
  // 参数:cb(遍历项、索引、数组本身)
  const arrMap = arr.map((item, index, arr) => item ** 2)
  console.log(arrMap)

  // 3、filter(过滤数组)
  // 参数:cb(遍历项、索引、数组本身)
  const arrFilter = arr.filter((item, index, arr) => item > 2)
  console.log(arrFilter)

  // 4、some(判断条件只要有一个为true,则返回true;全为false,则返回false)
  // 参数:cb(遍历项、索引、数组本身)
  const arrSome = arr.some((item, index, arr) => item > 0)
  console.log(arrSome)

  // 5、every(判断条件全为true,则返回true;有一个为false,则返回false)
  // 参数:cb(遍历项、索引、数组本身)
  const arrEvery = arr.every((item, index, arr) => item > 0)
  console.log(arrEvery)

  // 6、reduce(求和、统计元素出现的个数)
  // 参数:cb(上一次的返回值、当前元素、当前元素索引、数组本身)、preRes的初始值(若指定初始值,则curV从数组第一项开始;未指定,preRes取第一项,curV从数组第二项开始)
  const resReduce = arr.reduce((preRes, curV, curIndex, arr) => {
    return preRes + curV
  }, 6)
  console.log(resReduce)

  // 7、find(返回第一个满足条件的元素,没有则返回undefined)
  // 参数:cb(遍历项、索引、数组本身)
  const resFind = arr.find((item, index, arr) => item === 0)
  console.log(resFind)

  // 8、findIndex(返回第一个满足条件元素的索引,没有则返回-1)
  // 参数:cb(遍历项、索引、数组本身)
  const resFindIndex = arr.findIndex((item, index, arr) => item === 0)
  console.log(resFindIndex)

  // 9、includes(判断数组中是否包含一个指定的值,若存在,则返回true;不存在,则返回false)
  // 参数:指定元素、位置索引(从此处开始搜索,若 < 0 ,则搜索全部)
  const resIncludes = arr.includes(0)
  console.log(resIncludes)

  // 10、flat(数组的扁平化,数组空项会被移除)
  // 参数:提取嵌套数组的深度(默认为1,传入 Infinity 则展开任意深度的嵌套数组)
  const origin = [1, 2, [3, 4, [5, [6, 7]]], ,]
  const arrFlat = origin.flat(Infinity)
  console.log(arrFlat)

  // 11、flatMap(相当于flat + map)
  const origin1 = ['1 2 3', '4 5 6']
  const arrFlatMap = origin1.flatMap((item, index, arr) => item.split(' '))
  console.log(arrFlatMap)
  // 等同于
  const arrFlatMap1 = origin1.map(item => item.split(' ')).flat()
  console.log(arrFlatMap1)
}

12、ES6+ 对象方法

/**
 * @description ES6+ 对象方法
 */
const useObjFn = () => {
  const obj = {
    name: 'mei',
    age: 23,
    sex: 'male',
    sayHello () { console.log(`hi,my name is ${this.name}`) }
  }

  // 1、Object.key(获取对象的键的集合)
  console.log(Object.keys(obj))

  // 2、Object.values(获取对象的值的集合)
  console.log(Object.values(obj))

  // 3、Object.entries(获取对象的键值对的集合)
  console.log(Object.entries(obj))

  // 4、Object.freeze(冻结对象,被冻结的对象将不可被修改)
  Object.freeze(obj)
  // Uncaught TypeError: Cannot assign to read only property 'age' of object '#<Object>'
  // obj.age = 18

  // 5、Object.fromEntries(与entries相反,将键值对的集合转为对象)
  const key_val = [['name', 'mei'], ['age', 23]]
  console.log(Object.fromEntries(key_val))
}

13、随机生成20位序列值

/**
 * @description 随机生成20位序列值:当前时间 + 六位随机数
 * @description 需要具备 dayjs库
 * @returns 
 */
export const genRandowId = () => {

  const curTime = dayjs().format('YYYYMMDDHHmmss')
  let randomSixStr = ''

  for (let i = 0; i < 6; i++) {
    randomSixStr += String(Math.floor(Math.random() * 10))
  }

  return curTime + randomSixStr
}

14、页面滚动

/**
 * @description 页面滚动
 * @param {*} top 高度
 * @param {*} left 宽度
 * @param {*} behavior 行为 smooth(平滑)
 */
export const scrollTo = (top = 0, left = 0, behavior = 'smooth') => {
  document.documentElement.scrollTo({
    top,
    left,
    behavior
  })
}

15、去除数字之外的所有字符

/**
 * @description 去除数字之外的所有字符
 * @param {*} str 
 * @returns 
 */
export const getOnlyNumOfStr = (str = '') => {
  return str.replace(/\D/g, '')
}

16、反转字符串

/**
 * @description 反转字符串(按字符或单词)
 * @param {*} str 
 * @param {*} type char(字符)、word(单词)
 * @returns 
 */
export const reverseStr = (str = '', type = 'char') => {
  const typeMap = {
    'char': () => '',
    'word': () => ' '
  }

  return str.split(typeMap[type]()).reverse().join(typeMap[type]())
}

17、保留n位小数

/**
 * 保留n位小数
 * @param {*} num 
 * @param {*} n 
 * @returns 
 */
export const getFixedNum = (num, n = 2) => {
  num = Number(num)
  if (isNaN(num)) return '-'
  return Number(num.toFixed(num, n))
}

18、?. 、??、||=、&&=

/**
 * @description ?.(可选链操作符:读取对象的深处属性,若不存在不会报错,返回undefined,仅用于读取属性,不可用于赋值)
 * @description ??(合并空值操作符:操作符左侧值为null或undefined时,返回操作符右侧值)
 * @description ||=(a ||= b 等同于 a || a = b ,a为虚值时,给a赋值)
 * @description &&=(a &&= b 等同于 a && a = b ,a为实值时,给a赋值)
 */
const useOprSymbol = () => {
  // 1、?.
  const obj = {
    name: 'mei'
  }
  // undefined
  console.log(obj.prop?.sex)
  // Uncaught TypeError: Cannot read properties of undefined(reading 'sex')
  // console.log(obj.prop.sex)
  // Uncaught SyntaxError: Invalid left - hand side in assignment
  // obj?.name = 'meibo'

  // 2、??
  const [flag1, flag2, flag3] = [null, undefined, 'meibo']
  console.log(flag1 ?? 'mei')
  console.log(flag2 ?? 'mei')
  console.log(flag3 ?? 'mei')

  // 3、||=(无则赋值)
  obj.age ||= 23
  console.log(obj) // {name: 'mei', age: 23}

  // 4、&&=(有则赋值)
  obj.age &&= 18
  obj.sex &&= 'male'
  console.log(obj) // {name: 'mei', age: 18}
}

19、一种数据存储方式

/**
 * 一种数据存储方式
 */
const useObjMap = () => {
  const colorMap = {
    '需求': () => '#409EFF',
    '设计': () => '#67C23A',
    '开发': () => '#E6A23C',
    '测试': () => '#F56C6C',
    '部署': () => '#909399'
  }
  console.log(colorMap['开发']())
}

20、for await of

/**
 * @description for await of(循环遍历异步结果)
 */
const useForAwaitOf = async () => {

  const fn = timeout => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(timeout)
      }, timeout)
    })
  }
  // 正常用法
  const res1 = await fn(2000)
  console.log(res1)
  const res2 = await fn(1000)
  console.log(res2)
  const res3 = await fn(3000)
  console.log(res3)

  // for await of 用法
  const arr = [fn(2000), fn(1000), fn(3000)]
  for await (let res of arr) {
    console.log(res)
  }
}