扩展运算符 ... 就是把数组/对象摊平,跟 rest 正好相反。
核心三种:
① 数组展开——[...arr1, ...arr2] 合并数组
② 对象展开——{...obj1, ...obj2} 合并对象
③ 函数传参——fn(...arr)
坑:展开是浅拷贝、对象展开后面覆盖前面、数组合并用展开比 concat 直观。
把两袋零食倒在一个新袋子里,[...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); // ["王太利","肖央","曾毅","玲花"]
复制一份新数组,和原数组互不影响。
// 原数组 let arr = ["E", "G", "M"]; // 以前:slice 克隆 // slice() 不带参数就是复制一份 let copy = arr.slice(); // 现在:...arr 炸开再装回新 [] // 炸开 arr 装进新 [],得到副本 let copy = [...arr]; // 打印副本 console.log(copy); // ["E","G","M"]
克隆的意义:copy 和 arr 是两个独立数组,改 copy 不影响 arr。注意这是"浅克隆"——数组里如果是对象,对象还是同一个引用,改对象内容两边都会变。
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
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 全是这个套路。
① 可能在什么地方用:合并两个数组/对象、复制数组不改原数据、Math.max(...arr) 求最大、把 DOM 集合转成真数组、React 组件展开 props。
② 常见的问题:把 ... 用在等号左边(那是 rest)以为在复制;以为展开是深克隆(其实是浅克隆,嵌套对象还是共享);直接对 NodeList 调数组方法报错。
③ 解决思路:合并/克隆就用 [...arr] / {...obj};要深克隆嵌套对象用 JSON.parse(JSON.stringify(obj));DOM 结果先 [...divs] 再用数组方法。
| API | 作用 | 参数 | 返回值 | 代码示例 |
|---|---|---|---|---|
| ...arr | 把一整袋数组炸开成单独的值 | 可遍历对象 | 一串值 | let c = [...a, ...b]; |