网站

展开语法 | MDN

ES6 数组的扩展 | 阮一峰

引入

有时候需要把数组或对象里的元素”拆开”用到别的地方,比如合并两个数组、复制一个对象。

以前要用 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);

类数组对象转数组

NodeListarguments 等类数组对象可以用展开语法转成真数组。

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() 之后再用展开语法组合结果。