← 返回目录

8. 扩展运算符

扩展运算符 ... 就是把数组/对象摊平,跟 rest 正好相反。

核心三种:
数组展开——[...arr1, ...arr2] 合并数组
对象展开——{...obj1, ...obj2} 合并对象
函数传参——fn(...arr)

坑:展开是浅拷贝、对象展开后面覆盖前面、数组合并用展开比 concat 直观

8.1 互动演示

点按钮看 ... 的实际效果。

8.2 知识点讲解

① 合并数组:concat → [...a, ...b]

把两袋零食倒在一个新袋子里,[...a, ...b]a.concat(b) 更直观。

// 第一袋
let a = ["王太利", "肖央"];

// 第二袋
let b = ["曾毅", "玲花"];

// 以前:concat 方法
// 把 b 拼到 a 后面
let c = a.concat(b);

// 现在:... 把两袋都炸开,倒在新数组里
// ...炸开 a 和 b,装进新 []
let c = [...a, ...b];

// ^^^^ ^^^^
// 倒a 倒b
// 打印合并后的新数组
console.log(c);

// ["王太利","肖央","曾毅","玲花"]

② 克隆数组:slice → [...arr]

复制一份新数组,和原数组互不影响。

// 原数组
let arr = ["E", "G", "M"];

// 以前:slice 克隆
// slice() 不带参数就是复制一份
let copy = arr.slice();

// 现在:...arr 炸开再装回新 []
// 炸开 arr 装进新 [],得到副本
let copy = [...arr];

// 打印副本
console.log(copy);

// ["E","G","M"]

克隆的意义:copyarr 是两个独立数组,改 copy 不影响 arr。注意这是"浅克隆"——数组里如果是对象,对象还是同一个引用,改对象内容两边都会变。

③ 展开传参:Math.max(...nums)

Math.max 本来要你一个个写参数 Math.max(3, 9, 5, 1),现在数组一炸直接喂进去。

// 一组数
let nums = [3, 9, 5, 1];

// 以前:一个个下标传
// 手写四个下标
console.log(Math.max(nums[0], nums[1], nums[2], nums[3]));

// 9

// 现在:...nums 炸成 3, 9, 5, 1 喂进去
// ... 把数组炸成一串参数
console.log(Math.max(...nums));

// 9

④ 伪数组转真数组(DOM 操作必备)

document.querySelectorAll 返回的 NodeList、函数的 arguments 都是"类数组"——没有 map/filter。[...类数组] 一行转成真数组。

// 拿到的是 NodeList 类数组
let divs = document.querySelectorAll("div");

// NodeList 是类数组,没有 map / filter

// 一行转真数组
let arr = [...divs];

// 现在数组方法随便用
arr.map(d => d.textContent);

如果你直接对 querySelectorAll 的结果调 .map,会报错"map is not a function"。因为 NodeList 不是真数组——先用 [...divs] 展开转成真数组,数组方法才能用。

⑤ 对象也能展开(合并对象 / 复制对象)

ES2018 起 ... 也能用在对象上:复制、合并、加字段。

// 原对象
let user = { name: "大喇叭", age: 22 };

// 复制整个对象
let copy = { ...user };

// 复制并加一个新字段
let withId = { ...user, id: 100 };

// 打印合并后的新对象
console.log(withId);

// { name: "大喇叭", age: 22, id: 100 }

对象展开里后面的同名属性会覆盖前面的——所以写 { ...defaultConfig, ...userConfig } 时,用户配置永远盖在默认配置后面。React 里 {...props} 传属性、合并 state 全是这个套路。

8.3 实战:用在哪 / 常见坑 / 怎么解决

① 可能在什么地方用:合并两个数组/对象、复制数组不改原数据、Math.max(...arr) 求最大、把 DOM 集合转成真数组、React 组件展开 props。

② 常见的问题:... 用在等号左边(那是 rest)以为在复制;以为展开是深克隆(其实是浅克隆,嵌套对象还是共享);直接对 NodeList 调数组方法报错。

③ 解决思路:合并/克隆就用 [...arr] / {...obj};要深克隆嵌套对象用 JSON.parse(JSON.stringify(obj));DOM 结果先 [...divs] 再用数组方法。

一句话:... = 把数组/对象炸开,合并、克隆、传参、转数组一把梭;rest 是收,spread 是放。

本页重点

API作用参数返回值代码示例
...arr把一整袋数组炸开成单独的值可遍历对象一串值let c = [...a, ...b];