← 返回目录

8. 扩展运算符

... 把数组或对象"炸开"成一个个单独的值——像把一整袋零食撕开倒在桌上。它是 rest(收)的逆运算:rest 把剩下的东西收进袋子,spread 把袋子撒出来。用于合并、克隆、传参、转数组

8.1 互动演示

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

8.2 知识点讲解

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

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

let a = ["王太利", "肖央"]; // 第一袋
let b = ["曾毅", "玲花"];   // 第二袋

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

// 现在:... 把两袋都炸开,倒在新数组里
let c = [...a, ...b];       // ...炸开 a 和 b,装进新 []
//    ^^^^  ^^^^
//    倒a  倒b
console.log(c);             // 打印合并后的新数组
// ["王太利","肖央","曾毅","玲花"]

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

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

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

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

// 现在:...arr 炸开再装回新 []
let copy = [...arr];       // 炸开 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。[...类数组] 一行转成真数组。

let divs = document.querySelectorAll("div"); // 拿到的是 NodeList 类数组
// 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 是放。