网站
引入
有时候需要把数组或对象里的元素”拆开”用到别的地方,比如合并两个数组、复制一个对象。
以前要用 concat()、slice()、Object.assign() 等方法,写起来比较长。展开语法用 … 三步搞定这些事。
正文
定义
展开语法(Spread)用
…把数组或对象里的元素逐个展开,放到新的数组、对象或函数参数中。
数组展开
把数组里的元素展开到新数组里,实现合并。
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2];
console.log(merged);可以在展开的同时插入新元素:
const arr1 = [2, 3];
const arr2 = [6, 7];
const result = [1, ...arr1, 4, 5, ...arr2, 8];
console.log(result);数组浅拷贝
用展开语法可以快速复制一个数组。
const original = [1, 2, 3];
const copy = [...original];
copy.push(4);
console.log(original);
console.log(copy);注意这只是浅拷贝,如果数组里包含对象,对象本身还是同一个引用。
const original = [{ name: "Tom" }];
const copy = [...original];
copy[0].name = "Jack";
console.log(original[0].name);对象展开
把对象的属性展开到新对象里,实现合并。
const defaults = {
color: "red",
size: "medium",
active: false
};
const custom = {
color: "blue",
active: true
};
const result = { ...defaults, ...custom };
console.log(result);后面的对象属性会覆盖前面同名的属性。
展开时也可以添加或修改属性:
const user = {
name: "Tom",
age: 18
};
const updated = {
...user,
age: 19,
city: "北京"
};
console.log(updated);对象浅拷贝
const original = {
name: "Tom",
age: 18
};
const copy = { ...original };
copy.name = "Jack";
console.log(original.name);
console.log(copy.name);同样是浅拷贝,嵌套的对象不会被深复制。
剩余参数(Rest Parameters)
在函数定义中用 … 把多个参数收集到一个数组里。
function sum(...numbers) {
let total = 0;
for (const n of numbers) {
total = total + n;
}
return total;
}
console.log(sum(1, 2, 3));
console.log(sum(10, 20));剩余参数必须是最后一个参数:
function logFirst(first, ...rest) {
console.log(first);
console.log(rest);
}
logFirst("a", "b", "c", "d");函数调用时展开数组
把数组里的元素展开作为函数的参数。
const numbers = [5, 2, 8, 1, 9];
const max = Math.max(...numbers);
console.log(max);类数组对象转数组
NodeList、arguments 等类数组对象可以用展开语法转成真数组。
const divs = document.querySelectorAll("div");
const arr = [...divs];
arr.forEach(div => {
console.log(div.textContent);
});function example() {
const args = [...arguments];
console.log(args);
}
example(1, 2, 3);字符串展开
展开语法也可以把字符串拆成单个字符的数组。
const str = "hello";
const chars = [...str];
console.log(chars);常见写法
| 写法 | 说明 |
|---|---|
[…arr1, …arr2] | 合并数组 |
[…original] | 数组浅拷贝 |
{ …obj1, …obj2 } | 合并对象 |
{ …original } | 对象浅拷贝 |
{ …obj, key: val } | 拷贝并修改属性 |
function(…args) | 剩余参数,收集所有参数 |
fn(…arr) | 把数组展开为函数参数 |
[…str] | 字符串拆成字符数组 |
例子
合并配置
const defaultConfig = {
host: "localhost",
port: 3000,
debug: false
};
const userConfig = {
port: 8080,
debug: true
};
const config = { ...defaultConfig, ...userConfig };
console.log(config);向数组添加元素(不修改原数组)
const list = [1, 2, 3];
const newList = [...list, 4];
console.log(list);
console.log(newList);去掉数组中的重复值
const arr = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique);理解
展开语法可以理解为把容器里的东西一个个拿出来。
数组展开是把元素一个一个铺出来,对象展开是把属性一个一个列出来。
剩余参数刚好反过来,是把散落的参数收进一个数组里。
展开语法和解构赋值都用到 …,但方向相反:展开是”铺开”,解构是”拆出来”。
引出
展开语法和 JS 解构赋值 是一对互补的操作,一个铺开一个拆取。
在实际项目中,展开语法经常配合 JS 数组方法 使用,比如 map()、filter() 之后再用展开语法组合结果。