ES6 运算符扩展
之前讲函数里的 rest 参数,... 负责”把参数收集成数组”,现在轮到它相反的身份出场:展开运算符——把数组或对象”拆开展开”。
本篇以展开运算符为主角,同时收录两个日常高频、写法相关的运算符:可选链 ?. 和空值合并 ??(ES2020 推出,已广泛使用)。
展开运算符 ...
展开数组
把数组的元素”摊出来”,一个个传给函数或放进新数组:
// 示例:不用 apply,直接展开传给 Math.max
const nums = [3, 1, 4, 1, 5];
console.log(Math.max(...nums)); // 5
// 示例:合并数组
const a = [1, 2];
const b = [3, 4];
console.log([...a, ...b]); // [1, 2, 3, 4]
对比记忆:rest 参数把”散开的参数收到一起”,展开运算符把”数组摊开”。长相一样、方向相反。
复制与展开对象
展开运算符也能用于对象,非常适合”合并或浅拷贝对象”:
// 示例:复制对象(浅拷贝)
const base = { name: '小明', age: 20 };
const copy = { ...base };
console.log(copy); // { name: '小明', age: 20 }
// 示例:合并对象,后面的会覆盖同名键
const extra = { age: 30, city: '北京' };
const merged = { ...base, ...extra };
console.log(merged); // { name: '小明', age: 30, city: '北京' }
注意:展开对象是浅拷贝,只复制一层;嵌套的对象仍然共享同一个引用。
可选链 ?.(ES2020)
访问嵌套属性时,中间某级可能是 undefined 或 null,直接 . 会报错:
// 示例:如果 type 不存在,直接访问会报错
// user.profile.address.city —— 如果 profile 不存在就报 TypeError
可选链 ?. 遇到中间为 undefined/null 会短路返回 undefined,不报错:
// 示例
const user = {}; // 没有 profile
console.log(user.profile?.city); // undefined —— 不报错
console.log(user.profile?.list[0]); // undefined
常见场景:接口返回的数据字段可能缺失时很安全。Vue 模板里 v-for 数据对象、组件 props 上也很常用。
空值合并 ??(ES2020)
当左边的值是 null 或 undefined 时,才返回右边的默认值:
// 示例
const a = null;
const b = undefined;
const c = 0;
console.log(a ?? '默认'); // 默认
console.log(b ?? '默认'); // 默认
console.log(c ?? '默认'); // 0 —— 注意:0 不是 null/undefined,保留
对比 ||:0、''、false 这样”为假但合法”的值,|| 会错误地走默认值分支,?? 更符合直觉。
// 示例:0 被空值合并保留,不会丢失
console.log(0 || 100); // 100 —— 被 || 吞了
console.log(0 ?? 100); // 0 —— ?? 留给 0
注意:?? 不能直接和 ||、&& 混放在同一个表达式里,需要括号分开。
三个运算符的常见用途
| 场景 | 用法 |
|---|---|
| 展开参数调用 | fn(...arr) |
| 合并数组 | [...a, ...b] |
| 复制数组 | [...a] |
| 合并对象 | {...a, ...b} |
| 复制对象 | {...obj} |
| 安全取值 | obj?.a?.b |
| 默认值 | x ?? 默认值 |
掌握这三个运算符后,你写代码时很多”不敢写死”的地方都可以大胆放心写。