#### 一、 ...的两种含义

##### 1. 剩余参数运算符
• `定义函数`的时候使用运算符(...)，会将传过来的多余参数`合到一起`
• 剩余参数`永远是个数组`，即使没有值，也是空数组
• 剩余参数只能作为`最后`一个参数
``````const fn = (num1, num2, ...nums) => {
console.log(num1, num2, nums);
};
fn(1, 2); // 1 2 []
fn1(1, 2, 3, 4, 5, 6); // 1 2 [3,4,5,6]``````

##### 2. 展开运算符
``````const arr = ["css", "js", "ts", "vue"];
console.log(...arr); // css js ts vue``````

##### 3. 展开运算符和剩余参数运算符的区别
• `剩余参数`运算符：`1,3,5 --> [1,3,5]`
• `展开`运算符：`[1,3,5] --> 1,3,5`
``````const diff = (...args) => {
console.log(args); // 剩余参数运算符：[1,3,5]
console.log(...args); // 展开运算符：1,3,5
};
diff(1, 3, 5);``````

#### 二、 ...的用法举例

##### 1. 数组
###### （1）数组复制
``````const citys = ["南京", "北京", "上海", "成都", "杭州"];
const citysCopy = [...citys];
console.log(citysCopy); // ["南京", "北京", "上海", "成都", "杭州"]``````

###### （2）数组去重
``````const colors = ["red", "orange", "yellow", "green", "orange"];
const onlyColors = [...new Set(colors)];
console.log(onlyColors); // ["red", "orange", "yellow", "green"]``````

###### （3）数组合并
``````const animals = ["cat", "dog"];
const seasons = ["spring", "summer"];
const animalsAndSeasons = [...animals, ...seasons];
console.log(animalsAndSeasons); // ["cat", "dog", "spring", "summer"]``````

###### （4）数组切片
``````const digitals = ["pc", "watch", "camera", "keyboard", "mouse"];
const [pc, ...otherDigitals] = digitals;
console.log(otherDigitals); // ["watch", "camera", "keyboard", "mouse"]``````

###### （5）数组作为参数进行传递
• 数组个数`等于`形参个数：一一对应
• 数组个数`小于`形参个数：缺少值为 undefined
• 数组个数`大于`形参个数：多的参数值被忽略
• `调用函数`的时候使用运算符(...)，会把原本聚拢在一起的数据`拆分`传递给各个参数
``````const phone1 = ["apple", "vivo", "oppo"];
const phone2 = ["apple", "vivo"];
const phone3 = ["apple", "vivo", "oppo", "华为"];
const mixer = (brand1, brand2, brand3) => {
console.log(brand1, brand2, brand3);
};
mixer(...phone1); // 等于：一一对应，apple vivo oppo
mixer(...phone2); // 小于：缺少值为undefined，apple vivo undefined
mixer(...phone3); // 多于：多的参数值被忽略，apple vivo oppo``````

###### （6）将类数组转换为数组
``````const argsTransformArr = (...args) => console.log(args);
argsTransformArr("pineapple"); // ["pineapple"]
argsTransformArr(66, 88, 99); // [66, 88, 99]``````

##### 2. 对象
###### （1）复制对象
``````const student = {
name: "Jack",
school: {
class: "Software Engineering Class 2"
}
};
const studentCopy = { ...student };
console.log(studentCopy); // {name: "Jack",school:{class: "Software Engineering Class 3"}}``````

###### （2）合并对象——属性各不相同
• 新对象包含了合并的对象的`所有属性`
``````const personName = { name: "nina" };
const personSex = { sex: "female" };
const personAge = { age: 18 };
const person = { ...personName, ...personSex, ...personAge };
console.log(person); // {name: "nina", sex: "female", age: 18}``````

###### （3）合并对象——包含相同属性
• 合并的对象中包含有`同名的属性`，则后面对象中的属性值`覆盖`前面的同名的属性值
``````const fruit1 = {
name: "apple",
color: "red"
};

const fruit2 = {
name: "strawberry",
weight: "20g"
};

const fruit = { ...fruit1, ...fruit2 };
console.log(fruit); // {name: "strawberry", color: "red", weight: "20g"}``````

###### （4）内部属性为对象进行展开——内部对象不会展开
``````const fruit3 = {
detail: {
name: "apple",
size: "big",
weight: "300g"
}
};
console.log({ ...fruit3 });``````

###### （5）非对象展开
• 展开的是`空对象`，则仍然是空对象
• 展开的`不是对象`，则会自动将其转为对象，但是新创建的对象由于并`不包含任何属性`，故为空对象
``````console.log({ ...{} }); // {}

console.log({ ...1 }); // {}
console.log({ ...undefined }); // {}
console.log({ ...null }); // {}
console.log({ ...true }); // {}``````

##### 3. 数组与对象合并使用
``````const tableData1 = {
list: [
{ name: "张三", address: "南京" },
{ name: "李四", address: "北京" }
],
pageSize: 10,
pageNum: 1
};

const tableData2 = {
list: [
{ name: "王五", address: "深圳" },
{ name: "赵六", address: "上海" }
],
pageSize: 20,
pageNum: 2
};

const allTableDate = {
...tableData1,
list: [...tableData1.list, ...tableData2.list]
};
console.log(allTableDate);``````

##### 4. 字符串
``````const name = "Song";
console.log(...name); // 直接展开，S o n g
console.log([...name]); // 数组形式展开，["S", "o", "n", "g"]
console.log({ ...name }); // 对象形式展开，{0: "S", 1: "o", 2: "n", 3: "g"}``````

#### 三、 注意点

##### 1. 数组复制
• 通过运算符(...)拷贝`数组``值类型`的属性被`深度拷贝`了（用的`不同对象`），而引用类型的属性只是做了`浅拷贝`(复制的为`引用地址`，引用对象并未复制，即用的是`同一个对象`)
``````// 值类型
const citys = ["南京", "北京", "上海", "成都", "杭州"];
const citysCopy = [...citys];
citys[0] = "深圳";
console.log(citysCopy); // ["南京", "北京", "上海", "成都", "杭州"]``````

``````// 引用类型
let users = [
{
name: "小红",
sex: "female"
},
{
name: "小明",
sex: "male"
}
];
let usersCopy = [...users];
users[0].name = "小花";
console.info(usersCopy);``````

##### 2. 对象复制
• 通过运算符(...)拷贝`对象``值类型`的属性被`深度拷贝`了（用的`不同对象`），而引用类型的属性只是做了`浅拷贝`(复制的为`引用地址`，引用对象并未复制，即用的是`同一个对象`)
``````let user = {
name: "张三",
sex: "男",