关于ECMAScript 6 JavaScript实战开发小技巧(持续更新...)

422 阅读6分钟

1. reduce方法同时实现map和filter

假设现有一个数组,希望更新它的每一项(map),同时筛选一部分(filter)。如果先使用map然后filter,需要遍历数组两次,利用reduce简化写法

const numbers = [10, 20, 30, 40]
const doubledOver50 = numbers.reduce((finalList, num) => {
  num = num * 2
  if (num > 50) finalList.push(num)
  return finalList
}, [])
console.log('doubledOver50', doubledOver50) // [60, 80]

2. reduce方法统计数组中相同个数

let cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota']
let carsObj = cars.reduce((obj, name) => {
  obj[name] = obj[name] ? ++obj[name] : 1
  return obj
}, {})
console.log('carsObj', carsObj) // {BMW: 2, Benz: 2, Tesla: 1, Toyota: 1}

3.使用解构的小技巧

// 交换变量
let param1 = 1;
let param2 = 2;
[param1, param2] = [param2, param1]
console.log('param1', param1) // param1 2
console.log('param2', param2) // param2 1


// 解构返回值
async function getFullPost () {
  return await Promise.all([
    fetch('/post'),
    fetch('/comments')
  ])
}
const [post, comments] = getFullPost()

// 生成剩余数组
const [a, ...rest] = [...'asdf'] // a: 'a' rest: ['s', 'd', 'f']

// 数组浅拷贝
const arr = [1, 2, 3]
const arrClone = [...arr]
// 对象也可以浅拷贝
const obj = {a : 1}
const objClone = {...obj}
arr.slice(0, arr.length) / Array.from(arr)等方法同样也可以实现浅拷贝 ...操作符使用方便 代码也很简洁

// 数组合并
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr = [...arr1, ...arr2] //[1, 2, 3, 4, 5, 6]

// 数组取交集
const a = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
const duplicatedValues = [...new Set(a)].filter(item => b.includes(item))
console.log('duplicatedValues', duplicatedValues) // duplicatedValues [3, 4, 5]

// 数组取差集
const a = [0, 1, 2, 3, 4, 5]
const b = [3, 4, 5, 6, 7, 8]
const duplicatedValues = [...new Set([...a, ...b])].filter(item => !a.includes(item) || !b.includes(item))
console.log('duplicatedValues', duplicatedValues) // duplicatedValues [0, 1, 2, 6, 7, 8]

4.reduce方法数组扁平化

const flatten = (arr, depth = 1) =>   
  depth != 1     
    ? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), [])     
    : arr.reduce((a, v) => a.concat(v), [])
console.log(flatten([1, [2], 3, 4])) // [1, 2, 3, 4]
console.log(flatten([1, [2, [3, [4, 5], 6], 7], 8], 3)) // [1, 2, 3, 4, 5, 6, 7, 8]


// 还可以利用ES6中flat()方法进行数组扁平化
let arr1 = [1, [2], 3, 4] 
let arr2 = [1, [2, [3, [4, 5], 6], 7], 8] 
console.log(arr1.flat(Infinity)) // [1, 2, 3, 4]
console.log(arr2.flat(Infinity)) // [1, 2, 3, 4, 5, 6, 7, 8]

5.reduce方法判断数组最大值

const arr = ['s0', 's4', 's1', 's2', 's8', 's3']
const maxS = arr.reduce((prev, cur) => {
const curIndex = Number(cur.replace('s', ''))
  return curIndex > prev ? curIndex : prev
}, 0)
console.log('maxS', maxS) // maxS 8

6.利用reduce方法输出一个数组/对象

const arr = [1, 2, 3, 4, 5]
const value = arr.reduce((prev, curr) => {
  return curr % 2 === 0 ? [...prev, {value: curr}] : prev
}, [])

7.数组的对象解构

数组也可以对象解构,可以方便的获取数组的第n个值

const csvFileLine = '1997,John Doe,US,john@doe.com,New York';
const {2: country, 4: state} = csvFileLine.split(',')
console.log('country', country) // country US
console.log('state', state) // state New York

8.生成[1-100]的数组

new Array(100).fill(0).map((item, index) => index + 1)
Array.from(Array(100), (v, k) => k + 1)
[...Array(100).keys()]

new  Array(100)会生成一个有100空位的数组,这个数组是不能被map( ) forEach( ) filter( ) reduce( ) every( ) some( )遍历的的,因为空位会被跳过( for of不会跳过空位,可以遍历)。[...new Array(4)]可以给空位设置默认值undefined,从而使数组可以被以上方便遍历。

9.new Map()修改数组对象中某一属性值

// sz修改为深圳 bj修改为北京
let arr = [ { label: 1, placeCode: "sz" }, { label: 2, placeCode: "sz" }, { label: 3, placeCode: "bj" }, { label: 4, placeCode: "bj" }]

let maps = new Map([['sz', '深圳'],['bj', '北京']])

let filterArr = arr => {
 arr.map(item => item.placeCode = maps.get(item.placeCode))
 return arr
}

filterArr(arr)  //  { label: 1, placeCode: "深圳" },
                 // { label: 2, placeCode: "深圳" },
                 // { label: 3, placeCode: "北京" },
                 // { label: 4, placeCode: "北京" }

其它方法:
let toStr = {sz: '深圳', bj: '北京'}
arr.map(item => item.placeCode = toStr[item.placeCode] ? toStr[item.placeCode] : item.placeCode)

10.padStart( )补全字符串

let month = String(new Date().getMonth() + 1).padStart(2, '0')

12.padEnd( )改变时间戳

// 前端处理时间戳的时候单位是毫秒,后端返回的时间戳则不一样是毫秒,可能只有10位,
// 保险起见,要做一个13位的补全,保证单位是毫秒
let timetamp = +String(timetamp).padEnd(13, '0')

13.使用解构删除不必要属性

let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};
console.log('cleanObject', cleanObject) // cleanObject {el1: "1", el2: "2", el3: "3"}

14.在函数参数中解构嵌套对象

let car = {
  model: 'bmw 2018',
  engine: {
    v6: true,
    turbo: true,
    vin: 12345
  }
}
const modelAndVIN = ({model, engine: {vin}}) => {
  console.log(`model:${model} vin:${vin}`) // model:bmw 2018 vin:12345
}
modelAndVIN(car)

15.new Map( )对象优化(if else / switch)判断

场景一

判断某商品当前状态(1.开团进行中 2.开团失败 3.商品售完 4.开团成功 5.系统取消)

const actions = new Map([
  [1, ['processing']],
  [2, ['fail']],
  [3, ['fail']],
  [4, ['success']],
  [5, ['cancel']],
  ['default', ['other']]
])
const onButtonClick = status => {
  let action = actions.get(status) || actions.get('default')
  console.log('action', action[0]) // action success
}
onButtonClick(4)

场景二

判断某商品当前状态同时判断身份标识 (商品状态同上 身份标识: guset客态 master 主态)

// 处理方式一
const actions = new Map([
  ['guest_1', () => console.log('guest_1')],
  ['guest_2', () => console.log('guest_2')],
  // ...
  ['master_1', () => console.log('master_1')],
  ['master_2', () => console.log('master_2')],
  // ...
  ['default', () => console.log('default')]
])
const onButtonClick = (identity, status) => {
  let action = actions.get(`${identity}_${status}`) || actions.get('default')
  action.call(this)
}
onButtonClick('master', 2) // master_2
// 处理方式二
const actions = new Map([
  [{identity: 'guest', status: 1}, () => console.log('guest_1')],
  [{identity: 'guest', status: 2}, () => console.log('guest_2')],
  //...
])
const onButtonClick = (identity, status) => {
  let action = [...actions].filter(([key, value]) => key.identity === identity && key.status === status)
  action.forEach(([key, value]) => value.call(this))
}
onButtonClick('guest', 2) // guest_2

场景三

假如guest情况下 status 1-4处理逻辑都一样怎么办? 如何简化?

const actions = () => {
  const functionA = () => console.log('this is functionA')
  const functionB = () => console.log('this is functionB')
  return new Map([
    [/^guest_[1-4]$/, functionA],
    [/^guest_5$/, functionB]
    //...
  ])
}
const onButtonClick = (identity, status) => {
  let action = [...actions()].filter(([key, value]) => key.test(`${identity}_${status}`))
  action.forEach(([key, value]) => value.call(this))
}
onButtonClick('guest', 2) // this is functionA

16.string强制转换为数字

常用:使用 + 来转换字符串为数字

+ '123' // 123
+ 'ds' // NaN
+ '' // 0
+ null // 0
+ undefined // NaN
+ {value: () => '3'} // 3

17.使用Boolean过滤数组中所有假值

const compact = arr => arr.filter(Boolean)console.log(compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34])) // [1, 2, 3, "a", "s", 34]

18.双位运算符~~

双位运算符替代正数的Math.floor( ),替代负数的Math.ceil( ),双否定位操作又是在于它的执行相同的操作运行速度更快

Math.floor(4.9) === 4 // true
~~4.9 === 4 // true

Math.ceil(-4.5) // 4
~~-4.5 // 4

19.短路运算符

&&为取假运算,从左到右依次判断,如果遇到一个假值,就返回假值,以后不再执行,否则返回最后一个真值

||为取真运算,从左到右依次判断,如果遇到一个真值,就返回真值,以后不再执行,否则返回最后一个假值

// 变量赋初值
let variable1
let variable2 = variable1 || 'foo'

// 简单判断 取代冗长的if语句
let variable = param && param.prop

20. 取整 | 0

1.3 | 0 // 1
-1.9 | 0 // -1

21.判断奇偶数 & 1

对一个数字&1可以判断奇偶数,负数也同样适用**, num & 1**

const num = 3
!!(num & 1) // true
!!(num % 2) // true

22. 数组 对象互相转换方式

// 对象转换为数组
let obj = {name: 'xiaoming', age: '24'}
let arr = Object.keys(obj).map(key => obj[key])
console.log('arr', arr) // ["xiaoming", "24"]

// Object.values() Object.entries() 同样也可以

// 类数组转换为数组
let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};
let arr = Array.from(arrayLike);
console.log(arr); // ["a", "b", "c"]


// 数组转换为对象
// 对象转数组不能用展开操作符,因为展开操作符必须用在可迭代对象上
const arr = [1, 2, 3, 4]
const newObj = {...arr}
console.log('newObj', newObj) // newObj {0: 1, 1: 2, 2: 3, 3: 4}

23. Filter+Reduce过滤对象中为null的值

let obj = {
  name: null,
  list: ["1"]
}

const newObj = Object.keys(obj)
  .filter(key => obj[key] !== null)
  .reduce((prev, curr) => {
    if (typeof obj[curr] === "object") {
      prev[curr] = obj[curr].join(",")
    }
    return prev
  }, {})

console.log("newObj", newObj) // newObj {list: "1"}

参考链接:

www.zhangxinxu.com/wordpress/2…

JS字符串补全方法padStart()和padEnd()简介

blog.csdn.net/qq_40259641…

JavaScript复杂判断(if else / switch)的更优雅写法 优化冗余

juejin.cn/post/684490…

JS 中可以提升幸福度的小技巧

juejin.cn/post/684490…

JS数组奇巧淫技