7. 剩余参数 ...args
刚刚已经学过:
js
const newUser = {
...user
}
这里的 ... 是"展开"。
但如果 ... 出现在函数参数位置,意思就变了,叫:
剩余参数
例如:
js
function sum(...nums) {
console.log(nums)
}
sum(1, 2, 3)
输出:
js
[1, 2, 3]
这里:
js
...nums
意思是:
把传进来的剩余参数全部收集起来,组成一个数组。
7.1 为什么需要它
假设你不知道调用者会传几个数字:
js
sum(1, 2)
sum(1, 2, 3)
sum(1, 2, 3, 4, 5)
就可以:
js
const sum = (...nums) => {
let total = 0
nums.forEach(num => {
total += num
})
return total
}
调用:
js
console.log(sum(1, 2, 3))
// 6
7.2 前面可以有固定参数
例如:
js
function test(name, ...scores) {
console.log(name)
console.log(scores)
}
test('张三', 80, 90, 95)
结果:
text
张三
[80, 90, 95]
这里:
js
name
拿第一个参数。
剩下的:
js
80, 90, 95
全部进入:
js
scores
所以:
js
scores = [80, 90, 95]
7.3 ... 一定要放最后
正确:
js
function test(name, ...args) {
}
错误:
js
function test(...args, name) {
}
因为 JavaScript 不知道"剩余参数"到底应该收到哪里结束。
7.4 展开和剩余怎么区分
这是重点。
看位置。
展开
js
const arr2 = [...arr1]
意思:
把 arr1 拆开。
剩余
js
function test(...args) {
}
意思:
把剩余参数收集起来。
可以记:
text
放在数据里面 → 展开
放在函数参数里面 → 收集
例如:
js
const arr = [1, 2, 3]
console.log(...arr)
相当于:
js
console.log(1, 2, 3)
而:
js
const test = (...args) => {
console.log(args)
}
是反过来:
text
1, 2, 3
↓
[1, 2, 3]
8. 函数默认参数
以前写 JavaScript,经常会这样:
js
function getList(pageNum, pageSize) {
if (pageNum === undefined) {
pageNum = 1
}
if (pageSize === undefined) {
pageSize = 10
}
}
ES6 可以直接:
js
function getList(pageNum = 1, pageSize = 10) {
console.log(pageNum, pageSize)
}
调用:
js
getList()
结果:
text
1 10
调用:
js
getList(2)
结果:
text
2 10
调用:
js
getList(2, 20)
结果:
text
2 20
8.1 实战:分页参数
你做后台项目很常见:
js
const getOrderList = (pageNum = 1, pageSize = 10) => {
return request({
url: '/xxx/order/list',
method: 'get',
params: {
pageNum,
pageSize
}
})
}
调用:
js
getOrderList()
默认:
text
pageNum = 1
pageSize = 10
也可以:
js
getOrderList(3, 50)
8.2 默认参数和解构一起用
这种写法很实用:
js
function search({
pageNum = 1,
pageSize = 10,
status = ''
}) {
console.log(pageNum)
console.log(pageSize)
console.log(status)
}
调用:
js
search({
status: 'COMPLETED'
})
结果:
text
pageNum = 1
pageSize = 10
status = COMPLETED
这里其实同时用了:
text
解构赋值
+
默认参数
8.3 再保险一点
有时候调用:search() 会报错。
因为相当于在对:undefined 进行对象解构。
所以实际可以这样:
js
function search({
pageNum = 1,
pageSize = 10,
status = ''
} = {}) {
}
注意最后:
js
= {}
这表示:
如果整个参数都没传,就先给一个空对象。
所以:
js
search()
也不会报错。
这个写法在工具函数、公共函数里很实用。
9. 数组常用方法
这一块非常重要。
先记住 5 个:
text
map
filter
find
some
every
另外还有两个你肯定也会用:
text
forEach
reduce
但我们先把核心 5 个讲明白。
假设有一组用户数据:
js
const users = [
{
id: 1,
name: '张三',
age: 18,
enabled: true
},
{
id: 2,
name: '李四',
age: 25,
enabled: false
},
{
id: 3,
name: '王五',
age: 30,
enabled: true
}
]
9.1 map:把每一项转换成另一种东西
例如现在只想拿姓名:
js
const names = users.map(item => item.name)
结果:
js
['张三', '李四', '王五']
你可以理解成:
text
原数组
↓
逐个加工
↓
生成新数组
所以:
js
map
特别适合:
数据转换。
实战案例
后端返回:
js
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
]
前端下拉框需要:
js
[
{
label: '张三',
value: 1
},
{
label: '李四',
value: 2
}
]
可以:
js
const options = users.map(item => {
return {
label: item.name,
value: item.id
}
})
还可以简写:
js
const options = users.map(item => ({
label: item.name,
value: item.id
}))
注意这里有个小知识:
js
item => ({
})
为什么对象外面多一层括号?
因为:
js
item => {
}
JavaScript 会把 {} 当成函数体。
所以如果想直接返回对象,要:
js
item => ({
})
9.2 filter:过滤数据
假设只要启用用户:
js
const enabledUsers = users.filter(item => item.enabled)
结果:
js
[
{
id: 1,
name: '张三',
age: 18,
enabled: true
},
{
id: 3,
name: '王五',
age: 30,
enabled: true
}
]
如果只要年龄大于 20:
js
const result = users.filter(item => item.age > 20)
得到:
text
李四
王五
所以:
text
filter = 筛选
Vue 实战
例如:
js
this.tableData = response.rows.filter(item => item.status !== 'CANCELLED')
意思:
把所有取消状态的数据排除掉。
9.3 find:找到第一条符合条件的数据
例如:
js
const user = users.find(item => item.id === 2)
得到:
js
{
id: 2,
name: '李四',
age: 25,
enabled: false
}
注意:
js
find
返回的是:
一条数据。
而:
js
filter
返回的是:
一个数组。
这是两者最核心的区别。
对比一下
js
const result1 = users.filter(item => item.id === 2)
得到:
js
[
{
id: 2,
name: '李四'
}
]
是数组。
而:
js
const result2 = users.find(item => item.id === 2)
得到:
js
{
id: 2,
name: '李四'
}
直接就是对象。
没找到怎么办
js
const user = users.find(item => item.id === 100)
结果:
js
undefined
所以实际项目里经常:
js
const user = users.find(item => item.id === userId)
if (user) {
console.log(user.name)
}
9.4 some:有没有至少一个符合条件
这个在业务判断里特别好用。
例如:
js
const result = users.some(item => item.enabled)
意思:
有没有至少一个启用用户?
结果:
js
true
因为张三、王五都是启用状态。
假设维修项目
例如:
js
const parts = [
{
partName: '屏幕',
issuedQty: 0
},
{
partName: '电池',
issuedQty: 1
}
]
判断:
有没有备件已经领用了?
直接:
js
const hasIssued = parts.some(item => item.issuedQty > 0)
结果:
js
true
然后:
js
if (hasIssued) {
this.$message.warning('已有备件领用,不能取消工单')
return
}
这就是一个非常典型的业务场景。
9.5 every:是不是全部符合条件
例如:
js
const result = users.every(item => item.enabled)
意思:
是不是所有用户都启用了?
因为李四:
js
enabled: false
所以:
js
false
案例
例如维修方案有多个项目:
js
const items = [
{
name: '换屏',
confirmed: true
},
{
name: '换电池',
confirmed: true
}
]
判断:
是不是所有项目都已经确认?
js
const allConfirmed = items.every(item => item.confirmed)
结果:
js
true
如果其中一个:
js
confirmed: false
那么:
js
allConfirmed === false
some 和 every 最容易混
可以直接这么记:
text
some
=
有一个就行
every
=
必须全部满足
9.6 五个方法放一起看
还是:
js
const users = [
{ id: 1, name: '张三', age: 18, enabled: true },
{ id: 2, name: '李四', age: 25, enabled: false },
{ id: 3, name: '王五', age: 30, enabled: true }
]
map
js
users.map(item => item.name)
结果:
js
['张三', '李四', '王五']
意思:
转换。
filter
js
users.filter(item => item.age >= 20)
结果:
text
李四、王五组成的新数组
意思:
筛选多条。
find
js
users.find(item => item.id === 2)
结果:
text
李四这个对象
意思:
找一条。
some
js
users.some(item => item.enabled === false)
结果:
js
true
意思:
有没有一个满足。
every
js
users.every(item => item.age >= 18)
结果:
js
true
意思:
是不是全部满足。
一个真实业务案例
假设接口返回维修备件:
js
const parts = [
{
id: 1,
name: '屏幕',
quantity: 2,
status: 'USED'
},
{
id: 2,
name: '电池',
quantity: 1,
status: 'RETURNED'
},
{
id: 3,
name: '摄像头',
quantity: 1,
status: 'USED'
}
]
找到电池
js
const battery = parts.find(item => item.name === '电池')
获取所有已使用备件
js
const usedParts = parts.filter(item => item.status === 'USED')
获取备件名称
js
const partNames = parts.map(item => item.name)
结果:
js
['屏幕', '电池', '摄像头']
判断有没有退货
js
const hasReturned = parts.some(item => item.status === 'RETURNED')
判断是否全部已使用
js
const allUsed = parts.every(item => item.status === 'USED')
这种写法以后在前端进行状态判断、列表处理、接口数据转换时会大量使用。
顺便补一个 forEach
这个虽然不是 ES6 新增,但实战特别常见。
js
users.forEach(item => {
console.log(item.name)
})
它的目的通常就是:
遍历做事情。
和 map 最大区别是:
forEach
偏向:
text
遍历执行
例如:
js
users.forEach(item => {
item.checked = false
})
map
偏向:
text
处理后生成新的数组
例如:
js
const names = users.map(item => item.name)
所以不要为了遍历而乱用 map。
如果你根本不需要返回新数组:
js
users.map(item => {
console.log(item.name)
})
虽然能运行,但不推荐。
应该:
js
users.forEach(item => {
console.log(item.name)
})
第 7~9 个总结
现在可以记成:
text
7. 剩余参数 ...args
↓
收集函数参数
8. 默认参数
↓
参数没传时使用默认值
9. 数组方法
↓
map 转换
filter 筛选多条
find 找一条
some 至少一个满足
every 全部满足
尤其是第 9 个,我建议你把下面这一组直接记熟:
js
list.map(item => ...)
把数据转换成新数组。
js
list.filter(item => ...)
过滤数据。
js
list.find(item => ...)
找到第一条。
js
list.some(item => ...)
有没有符合条件的。
js
list.every(item => ...)
是不是全部符合条件。