3个点操作符
剩余参数
假设我们有这样的一个Object,存储学生年龄,如下:
var studentInfo = {
'张飞' : 18,
'赵云' : 17,
'许褚' : 16,
'典韦' : 18,
'关羽' : 19,
}
要实现一个函数 printAge
,它的输入参数是一些学生的姓名,函数需要打印出这些输入学生的年龄。
这里有个问题,就是调用printAge 时, 输入的学生名字 个数是不固定的,可能是1个、2个、100个, 甚至也可能是0个。
这肯定难不倒聪明的你, 你会使用数组作为参数类型, 数组里面每个元素存放要获取年龄信息的学生名。
像这样
var studentInfo = {
'张飞' : 18,
'赵云' : 17,
'许褚' : 16,
'典韦' : 18,
'关羽' : 19,
}
function printAge(students){
for (let student of students) {
console.log(`学生:${student} , 年龄 ${studentInfo[student]}`);
}
}
printAge(['张飞', '典韦', '关羽'])
printAge(['赵云'])
运行一下看看, 完全没有问题。
但是我们似乎觉得,如果调用该函数的时候,能把下面这种写法
printAge(['张飞', '典韦', '关羽'])
改为
printAge('张飞', '典韦', '关羽')
这样调用。 显得更加易读易懂。
但是问题就在于,因为这个函数参数的 个数是不确定的
,函数如何定义呢?
js中可以使用 , 使用三个点操作符 ...
, 这样定义
function printAge(...students){
for (let student of students) {
console.log(`学生:${student} , 年龄 ${studentInfo[student]}`);
}
}
和上面相比,唯一的改动就是, 参数名前面加了3个点。
然后我们就可以这样调用该函数了
printAge('张飞', '典韦', '关羽')
printAge('赵云')
效果和前面一种定义完全一样。
这种前面加 3个点 的参数,称之为 剩余参数(rest parameters) 。
执行函数时,它是一个 数组
,里面存放所有 所有未被对应的 剩余参数值。
也就是说,上面的例子里面,如下调用代码执行的时候,
printAge('张飞', '典韦', '关羽')
js解释器创建一个 数组 赋值给这个 students,里面存放了 ‘张飞’, ‘典韦’, ‘关羽’ 三个字符串对象作为元素,
我们在代码里加入一行语句,显示 students 参数
var studentInfo = {
'张飞' : 18,
'赵云' : 17,
'许褚' : 16,
'典韦' : 18,
'关羽' : 19,
}
function printAge(...students){
console.log(students)
for (let student of students) {
console.log(`学生:${student} , 年龄 ${studentInfo[student]}`);
}
}
printAge('张飞', '典韦', '关羽')
运行结果显示
[ '张飞', '典韦', '关羽' ]
学生:张飞 , 年龄 18
学生:典韦 , 年龄 18
学生:关羽 , 年龄 19
说明 students变量确实是对应一个数组。
剩余参数往往不是单独出现在函数参数中的,可以和其它参数一起出现
比如
var studentInfo = {
'张飞' : 18,
'赵云' : 17,
'许褚' : 16,
'典韦' : 18,
'关羽' : 19,
}
function printAge(prefix, ...students){
console.log(students)
for (let student of students) {
console.log(`${prefix} 学生:${student} , 年龄 ${studentInfo[student]}`);
}
}
printAge('-->', '张飞', '典韦', '关羽')
printAge('==>', '张飞', '典韦', '关羽')
这时,先把其它参数赋值完毕, 剩余的参数对象 放到 剩余参数对应的数组中。
展开语法
printAge 使用上面这样的剩余参数,假如我们要传入的参数恰好已经在一个数组 中,比如
var onebatch = ['张飞', '典韦', '关羽']
怎么调用printAge呢?
当然可以这样
printAge (onebatch[0], onebatch[1], onebatch[2])
显然不方便。
其实,我们还可以使用三个点操作符 ...
可以这样
printAge(...onebatch)
在调用时,这就是 展开语法(Spread syntax) 。
我们可以将其等价于
printAge (onebatch[0], onebatch[1], onebatch[2])
数据展开,不仅仅使用在调用函数的时候。
比如
var batch1 = ['张飞', '典韦', '关羽']
var batch2 = [...batch1, '赵云', '马超']
console.log(batch2)
这样, batch2 的前3个元素就是 batch1,里面的元素。
数据展开,还可以用于 Object,比如
var studentInfo1 = {
'张飞' : 18,
'赵云' : 17,
'许褚' : 16,
'典韦' : 18,
'关羽' : 19,
}
var studentInfo2 = {
...studentInfo1,
'黄忠' : 78,
'张辽' : 39,
}
这样,studentInfo2的值为
{
'张飞': 18,
'赵云': 17,
'许褚': 16,
'典韦': 18,
'关羽': 19,
'黄忠': 78,
'张辽': 39
}
可以多次使用数据展开,比如
var studentInfoAll = {
...studentInfo1,
...studentInfo2
}
这样可以实现多个Object 的合并,其中重复的数据会被后面的Object里面的值替换。
注意
var studentInfo = {
'黄忠' : 78,
'张辽' : 39
}
// 赋值1
var studentInfoAll_clone1 = studentInfo
// 赋值2
var studentInfoAll_clone2 = { ...studentInfo}
两个赋值语句,看起来好像最终内容相同,但是效果有很大差别。
赋值1 语句写法,studentInfoAll_clone1 只是 对象的新变量名, 和 studentInfo 对应的是同一个数据对象
而 赋值1 语句写法,studentInfoAll_clone2 对应的是一个新的对象。
studentInfoAll_clone1 === studentInfo // 结果为true
studentInfoAll_clone2 === studentInfo // 结果为false