JavaScript展开语法完全指南:从核心原理到避坑实践

更新日期: 2026-04-02 阅读: 6 标签: 语法

展开语法在函数调用、数组字面量中使用时,仅支持可迭代对象。


什么是可迭代对象

可迭代对象就是能被for...of循环逐个遍历的对象,它的底层特征是实现了JavaScript的迭代器协议,简单说就是对象内部有一个[Symbol.iterator]方法。

常见可迭代对象(开发常用)

  • 基础类型:数组、字符串

  • 集合类型:Set、Map

  • 其他:函数的arguments对象、DOM的NodeList节点集合

非可迭代对象(高频易错)

普通字面量对象{ key: value }不是可迭代对象,直接在数组/函数中展开普通对象会报错。

一句话总结:可迭代对象就是"能挨个取出元素的集合",展开语法的核心就是拆这个集合的元素。


一、展开语法的核心定义与基础语法

1. 核心定义

展开语法(符号为...,三个连续英文点,无空格),允许将可迭代对象(数组、字符串等)或普通对象,在需要多个元素/键值对的位置,拆分为单个的元素/键值对直接使用。

2. 基础语法格式

展开语法只有三个核心使用场景,覆盖99%的开发需求:

// 场景1:函数调用时,展开作为单个参数
fn(a, ...可迭代对象, b)

// 场景2:数组字面量中,展开作为数组元素
[1, ...可迭代对象, '3', 4]

// 场景3:对象字面量中,展开作为键值对
{ ...普通对象, newKey: 'newValue' }

核心原则:...后紧跟的对象类型必须匹配场景,否则会报错。


二、展开语法的三大核心实战场景

场景1:函数调用时使用展开语法

核心作用:将可迭代对象展开为函数的单个参数,替代传统的Function.prototype.apply()方法。

旧方法:apply传参(繁琐)

function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];

// ES6前:apply传参
sum.apply(null, numbers); // 结果:6

新方法:展开语法传参(简洁)

sum(...numbers); // 结果:6

进阶用法(开发常用)

可混合普通参数和展开参数,也可多次使用展开语法:

function calc(v, w, x, y, z) {
  return v + w + x + y + z;
}
const args1 = [1, 2];
const args2 = [4];

calc(0, ...args1, 3, ...args2); // 0+1+2+3+4 = 10

独家优势:支持new构造函数传参

apply只能执行函数的调用行为,无法用于new关键字,而展开语法可以直接在构造函数中使用:

const dateArr = [2024, 9, 1];
const newDate = new Date(...dateArr); // 构造2024-10-01的日期对象

场景2:数组字面量中使用展开语法

核心作用:快速实现数组创建、浅拷贝、合并、插入,替代传统的concat()/slice()/unshift()。

用法1:快速拼接创建新数组

const base = ["前端", "Java"];
const tech = ["Python", ...base, "Go", "PHP"];
console.log(tech); // ['Python', '前端', 'Java', 'Go', 'PHP']

用法2:数组浅拷贝

const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // 浅拷贝arr1

arr2.push(4);
console.log(arr1); // [1,2,3] 原数组不受影响
console.log(arr2); // [1,2,3,4] 新数组正常修改

用法3:合并多个数组

const arr1 = [0, 1];
const arr2 = [2, 3];
const arr3 = [4, 5];

const allArr = [...arr1, ...arr2, ...arr3]; // [0,1,2,3,4,5]

用法4:向数组开头插入元素

const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];

const newArr = [...arr2, ...arr1]; // [3,4,5,0,1,2]

重要坑点:浅拷贝的局限性

const a = [[1], [2], [3]];
const b = [...a]; // 浅拷贝

b[0].shift(); // 移除b[0]中的1
console.log(a); // [[], [2], [3]] 原数组也被修改

场景3:对象字面量中使用展开语法

这是ES2018(ES9)新增的特性,用于将普通对象的可枚举属性拆分为键值对,实现对象的克隆和合并。

用法1:对象浅拷贝

const user = { name: "小明", age: 20 };
const userClone = { ...user };
console.log(userClone); // { name: '小明', age: 20 }

用法2:合并多个对象

后面对象的同名属性会覆盖前面的:

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const obj3 = { d: 5 };

const mergeObj = { ...obj1, ...obj2, ...obj3 };
console.log(mergeObj); // { a: 1, b: 3, c: 4, d: 5 }

用法3:合并并新增/修改属性

const user = { name: "小明", age: 20 };
const newUser = { ...user, age: 21, gender: "男" };
console.log(newUser); // { name: '小明', age: 21, gender: '男' }

与Object.assign()的核心区别:Object.assign()会触发对象的setter方法,而展开语法不会触发setter。


三、展开语法的4个必避坑注意事项

1. 数组/函数场景,禁止直接展开普通对象

const obj = { a: 1, b: 2 };
// 错误:obj不是可迭代对象
const arr = [...obj]; // TypeError: obj is not iterable

// 正确:展开对象的键或值到数组
const keys = [...Object.keys(obj)];   // ['a', 'b']
const values = [...Object.values(obj)]; // [1, 2]

2. 函数调用时,展开参数有长度限制

JavaScript引擎对函数的参数个数有默认限制(约10万个),超过会报RangeError。日常开发中基本不会遇到。

3. 对象展开仅复制表层可枚举属性

const proto = { x: 1 };
const obj = Object.create(proto, { y: { value: 2, enumerable: true } });

const newObj = { ...obj };
console.log(newObj); // { y: 2 },原型的x不会被展开

4. 浅拷贝是通用特性

无论是数组还是对象,展开语法都只做浅拷贝,深层的引用类型会共享内存。


四、易混点:展开语法 vs 剩余参数(...)

特性展开语法剩余参数
核心作用拆:将集合拆分为单个元素/键值对合:将多个单个元素/参数合并为集合
使用位置函数调用、数组字面量、对象字面量函数参数、数组解构、对象解构
操作对象可迭代对象/普通对象多个单个的参数/元素
书写规则无位置限制必须写在最后

展开语法:拆(把集合变单个)

// 函数调用:拆数组为参数
sum(...[1,2,3]);

// 数组字面量:拆数组为元素
[...[1,2], 3];

// 对象字面量:拆对象为键值对
{ ...{a:1}, b:2 };

剩余参数:合(把单个变集合)

// 函数参数:合多个参数为数组
function fn(...args) { console.log(args); }
fn(1,2,3); // args = [1,2,3]

// 数组解构:合多个元素为数组
const [a, ...rest] = [1,2,3]; // a=1, rest=[2,3]


五、浏览器与运行环境兼容性

  • 数组/函数展开(ES6):Chrome 46+、Firefox 16+、Safari 8+、Node.js 5+

  • 对象展开(ES9):Chrome 60+、Firefox 55+、Safari 11.1+、Node.js 8.3+


六、核心知识点总结

  1. 核心作用:拆集合为单个元素/键值对,仅三个核心场景——函数调用、数组字面量、对象字面量

  2. 关键特性:仅做浅拷贝,数组/函数场景仅支持可迭代对象,对象展开会覆盖同名属性,仅复制可枚举属性

  3. 易混区分:和剩余参数是相反操作,展开拆、剩余合

  4. 开发避坑:不直接展开普通对象到数组/函数,注意浅拷贝的深层引用问题

掌握展开语法后,能大幅简化数组和对象的操作代码,让你的JS代码更优雅、更简洁。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13552

相关推荐

JS 新语法「可选链」「双问号」已进入 Stage 3

你希望如果 response 或者 response.settings 或者 response.settings.n 不存在(值为 null 或者 undefined)时,result 保底值为 100。但是上面代码在 n 为 0 的时候,也会让 result 变成 100,你实际上希望此时 result 为 0。

30-seconds-code:总结了大量的使用ES6语法实现的代码块

30-seconds-code这个项目是一个非常优秀的JavaScript项目,这里总结了大量的使用ES6语法实现的代码块,项目的设计目标就是更简洁,更高效,更快速的实现基础代码模块。

.htaccess文件RewriteRule语法规则

.htaccess文件是运行Apache Web Server的Web服务器的配置文件,对配置和重定向Apache Web Server文件系统很有用。在这里,我将讨论.htaccess文件RewriteRule语法规则。

如何让Node.js支持ES6的语法【转载】

不同版本的Node.js对Babel有不同的支持力度。为了让Node.js支持所需的ES6语法,可以加入Babel的支持。

js基本语法

JavaScript是一种轻量性脚本语言 ,其语句以;结束,语句块用{...},js应许末尾不加,浏览器Js引擎会自动在每个语句的结尾补上,js功能主要是:动态修改html页面内容,包括创建、删除html页面元素、修改html页面元素的内容

es6 Module语法

export用于定义要输出的变量(let、var、const、function、class),定义的变量与值是动态绑定关系。匿名定义本质上是采用 default 为名称,与上面2个的区别是在加载时可以不用写大括号还能自定义名称。

es6中的语法_面试es6常用语法整理

箭头函数;扩展运算符 ...的一个通用的用法就是把对象展开;变量声明es6中不建议继续使用var来声明变量,推荐使用let和const声明,以此避免var声明存在的弊端

JavaScript 语法流派现状调查

我们通常会有意无意的把JavaScript和其他编程语言区分开,有一个重要因素是……由于它的特性本身(太灵活了吧),它似乎不仅仅是一种语言,而更像是一帮老司机在矫情造作之下乱伦出来的生态系统。

带@的css语法,你知道多少?

css的顶层样式表由两种规则组成的规则列表构成,一种称为at—rule规则,也就是at规则,另一种是qualified rule,也就是普通规则。今天就学习一下at规则

css中的important是什么意思?

在HTML网页中css样式是根据优先级来判断使用的,优先级高的css样式会覆盖优先级低的样式,而css属性有很多都具有继承性,这就会影响我们网页显示,我们可以使用!important来改变这种情况。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!