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()简介
JavaScript复杂判断(if else / switch)的更优雅写法 优化冗余
JS 中可以提升幸福度的小技巧
JS数组奇巧淫技