超详细版ES6语法入门:展开运算符使用场景

从零搞懂 ES6 展开运算符:不只是...那么简单

你有没有写过这样的代码?

const result = Array.prototype.slice.call(arguments);

或者为了合并两个数组,翻出文档查concat的用法?又或者在 React 组件里为了一键透传所有 props,绞尽脑汁地手动列出来?

如果你点头了——恭喜,这篇文章就是为你准备的。我们不讲术语堆砌,也不照搬 MDN 文档,而是用实战视角重新认识那个看似简单、实则威力巨大的语法糖:展开运算符(Spread Operator)

它不是什么高深莫测的新技术,但却是现代 JavaScript 开发中出现频率最高、最容易被低估的工具之一。掌握它,你的代码会变得更干净、更安全、更具函数式风格。


什么是展开运算符?先别急着看定义

我们先来看一个最直观的例子:

const nums = [1, 2, 3]; console.log(nums); // [1, 2, 3] console.log(...nums); // 1 2 3

注意第二行输出的结果:1 2 3,不再是数组,而是三个独立的参数。

换句话说,...做了一件事:把“打包”的数据“拆开”

这个“拆”的过程,就是“展开”。

它的正式名字叫Spread Syntax(展开语法),写成...variable,作用是将可迭代对象或可枚举对象中的每一项“拉平”成单独的值,插入到当前表达式中。

✅ 支持类型包括:数组、字符串、Set、Map、arguments、NodeList、TypedArray,以及普通对象(ES2018 起支持)。
❌ 不支持nullundefined,否则会报错。


它是怎么工作的?背后没有魔法

JavaScript 引擎内部有一套叫做Iterator Protocol(迭代协议)的机制。任何实现了[Symbol.iterator]()方法的对象,都可以被for...of遍历,也就可以被...展开。

比如数组:

[1, 2, 3][Symbol.iterator](); // 返回一个迭代器

所以当你写:

Math.max(...[1, 5, 3]);

引擎实际上做了这件事:

Math.max(1, 5, 3); // 相当于直接传参

整个过程由语言层面自动完成,无需手动循环,既高效又语义清晰。


真正强大的地方:7 个高频使用场景

与其死记硬背语法,不如直接上战场。下面这些例子,全来自真实项目中的高频痛点。


场景一:数组合并与复制 —— 再也不用.concat()

传统方式:

const arr1 = [1, 2]; const arr2 = [3, 4]; const merged = arr1.concat(arr2); // [1,2,3,4]

ES6 写法:

const merged = [...arr1, ...arr2]; // 更直观,还能加新元素 const extended = [...arr1, 0, ...arr2]; // [1,2,0,3,4]

复制数组呢?

const copy = [...arr1]; // 比 slice() 还简洁

这招在 React 或 Redux 中尤其重要:永远不要直接修改 state。通过展开创建新数组,实现不可变更新(immutability),让状态变化可追踪、可调试。

⚠️ 注意:这是浅拷贝!如果数组里有对象,改子项仍会影响原数据:

js const nested = [{ name: 'Alice' }]; const copy = [...nested]; copy[0].name = 'Bob'; console.log(nested[0].name); // 'Bob' → 原数组也被改了!

深层嵌套需配合递归或库(如 immer),但大多数情况下,浅拷贝已足够。


场景二:字符串也能展开?对,而且比 split 更靠谱

你想把"hello"变成['h','e','l','l','o'],可能会这么写:

"hello".split(''); // ['h','e','l','l','o']

但遇到 emoji 呢?

"👨‍👩‍👧".split(''); // 结果可能是一堆乱码字符,因为 emoji 是组合符号

而展开运算符能正确识别 Unicode 复合字符(在支持环境下):

[..."👨‍👩‍👧"]; // ['👨‍👩‍👧'] → 正确识别为一个整体

所以在做密码强度检测、输入过滤、文本分析时,优先考虑[...str]而非split('')


场景三:函数传参新姿势 —— 告别.apply(null, args)

以前想把数组当参数传给函数,得靠apply

function sum(a, b, c) { return a + b + c; } const args = [1, 2, 3]; sum.apply(null, args); // 6

现在只需一行:

sum(...args); // 6,干净利落

尤其调用内置函数时特别方便:

Math.max(...[1, 8, 5, 9]); // 9 Math.min(...[1, 8, 5, 9]); // 1

⚠️ 小心陷阱:JavaScript 引擎对函数参数数量有限制(通常约 65536)。超大数组别硬来,改用reduce

js const max = largeArr.reduce((a, b) => Math.max(a, b), -Infinity);


场景四:对象克隆与合并 ——{...obj}Object.assign更优雅

要复制一个对象,老办法是:

const user = { name: 'Alice', age: 25 }; const clone = Object.assign({}, user);

现在可以:

const clone = { ...user }; // 一样的效果,更短

合并配置项也很常见:

const defaults = { theme: 'light', lang: 'zh', timeout: 5000 }; const userPrefs = { lang: 'en', theme: 'dark' }; const config = { ...defaults, ...userPrefs }; // { theme: 'dark', lang: 'en', timeout: 5000 }

后出现的属性覆盖前面的,逻辑清晰,适合默认配置 + 用户自定义的场景。

🔍 注意细节:
- 只复制自身可枚举属性,原型链上的不会被带上;
-Symbol类型的 key 不会被展开;
- 同样是浅拷贝,对象内的引用仍然共享。


场景五:和剩余参数(Rest Parameters)搭档,写出灵活 API

展开运算符有个好兄弟叫剩余参数(Rest),长得一样...,但用途相反:它是“收拢”而不是“展开”。

function log(prefix, ...messages) { messages.forEach(msg => console.log(`[${prefix}] ${msg}`)); } log('INFO', '启动中...', '加载资源'); // 输出: // [INFO] 启动中... // [INFO] 加载资源

这里...messages把剩下的参数收集成数组,再配合forEach使用。

更进一步,我们可以封装一个带时间戳的日志装饰器:

const withTimestamp = (fn, prefix) => (...args) => { fn(prefix, new Date().toISOString(), ...args); }; const timedLog = withTimestamp(console.log, 'TIMESTAMP'); timedLog('应用启动'); // TIMESTAMP 2025-04-05T10:00:00Z 应用启动

看到没?...args接收所有参数,...args又把它展开传递下去——形成完美闭环。

这类模式广泛用于中间件、埋点、权限拦截等需要动态处理参数的场景。


场景六:DOM NodeList 转数组?一行搞定

你一定遇到过这个问题:

const divs = document.querySelectorAll('div'); divs.map; // undefined!因为它不是真正的数组

querySelectorAll返回的是NodeList,类数组但不能用mapfilter

传统解法:

const arrayDivs = Array.prototype.slice.call(divs);

现在只需要:

const arrayDivs = [...divs];

然后就能愉快地链式操作了:

const wideActiveDivIds = [...document.querySelectorAll('.active')] .filter(div => div.offsetWidth > 100) .map(div => div.id);

这种写法在 SPA 动态渲染、表单校验、动画控制中极为常见。


场景七:数组去重神器 ——Set+ 展开 = 一行解决

要去掉重复元素,你会怎么写?

const unique = Array.from(new Set([1, 2, 2, 3, 3, 4])); // [1,2,3,4]

其实还可以更短:

const unique = [...new Set([1, 2, 2, 3, 3, 4])];

利用Set自动去重的特性,再通过展开还原为数组。目前公认最简洁的去重方案。

适用于标签管理、选项去重、历史记录清理等功能模块。


在现代前端架构中扮演什么角色?

展开运算符早已渗透进各个开发层级:

架构层典型用法
视图层React/Vue 中 props 扩展、class 名拼接
状态管理Redux 中 state 更新,确保不可变性
工具函数替代 Lodash 的部分功能,减少依赖
请求封装动态构造 headers、query 参数

特别是在 React 中,几乎每天都在用:

const Button = ({ className, ...props }) => ( <button className={`btn ${className}`} {...props} // 所有其他属性自动透传 /> );

这种“属性收集 + 展开透传”的模式,已经成为高级组件设计的标准范式。


实战建议:怎么用才不容易踩坑?

✅ 推荐做法

  1. 优先使用展开代替老方法

js // 好 const newArr = [...arr]; const newObj = { ...obj };

  1. 结合解构使用,提升代码表达力

js const [first, ...rest] = [1, 2, 3, 4]; console.log(first); // 1 console.log(rest); // [2, 3, 4]

  1. Redux reducer 中的安全更新

js case 'ADD_USER': return { ...state, users: [...state.users, action.payload] };


❌ 避免这些错误

  1. 误以为是深拷贝

js const obj = { user: { name: 'Alice' } }; const copy = { ...obj }; copy.user.name = 'Bob'; console.log(obj.user.name); // Bob → 出乎意料!

  1. 在超大数组上滥用展开

js Math.max(...hugeArray); // 可能栈溢出

  1. 在对象展开时忽略 Symbol 和不可枚举属性

js const obj = { [Symbol('id')]: 123 }; console.log({ ...obj }); // {} → 看不见 Symbol!


写到最后

展开运算符不是一个炫技的语法,而是一个真正提升开发效率、增强代码健壮性的实用工具

它让你少写几行代码的同时,也让逻辑更清晰、副作用更可控。尤其是在 React、Vue、Redux 这些强调不可变性和组件复用的框架中,它几乎是每日必用的存在。

更重要的是,它代表了一种思维方式的转变:从命令式到声明式,从手动操作到抽象表达

下次当你想调用concatsliceapply的时候,停下来想想:能不能用...一行搞定?

也许你会发现,JavaScript 没那么难,只是我们一直用老方法写着新代码。

如果你正在学习 ES6,不妨把今天这七个场景抄一遍、跑一遍、改一遍。等哪天你在代码评审中看到别人还在用Array.prototype.slice.call(arguments),你可以微微一笑:

“兄弟,试试...args?”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1151736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI人体骨骼检测二次开发:自定义关节点连接逻辑修改

AI人体骨骼检测二次开发&#xff1a;自定义关节点连接逻辑修改 1. 背景与需求分析 随着AI在运动分析、虚拟试衣、康复训练等领域的广泛应用&#xff0c;人体骨骼关键点检测已成为计算机视觉中的核心技术之一。Google的MediaPipe Pose模型凭借其高精度、低延迟和轻量化特性&am…

MediaPipe Pose保姆级教程:从零开始搭建人体骨骼检测系统

MediaPipe Pose保姆级教程&#xff1a;从零开始搭建人体骨骼检测系统 1. 引言 1.1 AI 人体骨骼关键点检测的现实需求 在智能健身、动作捕捉、虚拟试衣和人机交互等前沿领域&#xff0c;人体骨骼关键点检测&#xff08;Human Pose Estimation&#xff09;正成为核心技术支撑。…

AI人体骨骼检测部署教程:告别ModelScope,零报错本地运行

AI人体骨骼检测部署教程&#xff1a;告别ModelScope&#xff0c;零报错本地运行 1. 引言 1.1 学习目标 本文将带你从零开始&#xff0c;完整部署一个基于 Google MediaPipe Pose 的高精度 AI 人体骨骼关键点检测系统。你将学会如何在本地环境中快速搭建 WebUI 服务&#xff…

YOLOv8功能全测评:工业级目标检测真实表现

YOLOv8功能全测评&#xff1a;工业级目标检测真实表现 1. 引言&#xff1a;工业场景下的目标检测新标杆 在智能制造、智能安防、无人巡检等工业级应用中&#xff0c;实时性、稳定性与高召回率是目标检测系统的核心诉求。传统模型往往在速度与精度之间难以兼顾&#xff0c;而 …

ES6模块化项目应用:构建可维护的代码架构

用 ES6 模块化打造现代前端架构&#xff1a;从零构建可维护、可扩展的代码体系你有没有遇到过这样的场景&#xff1f;项目越做越大&#xff0c;main.js文件已经膨胀到几千行&#xff0c;函数之间牵一发而动全身&#xff1b;新同事接手时一脸茫然&#xff1a;“这个utils.js到底…

YOLOv8功能全测评:工业场景下的物体识别真实表现

YOLOv8功能全测评&#xff1a;工业场景下的物体识别真实表现 在智能制造、智慧安防、自动化巡检等工业场景中&#xff0c;目标检测技术正扮演着“视觉中枢”的关键角色。而YOLOv8作为Ultralytics推出的最新一代实时检测模型&#xff0c;凭借其高精度、低延迟、易部署的特性&am…

AI骨骼检测模型选型指南:MediaPipe为何适合生产环境?

AI骨骼检测模型选型指南&#xff1a;MediaPipe为何适合生产环境&#xff1f; 1. 引言&#xff1a;AI人体骨骼关键点检测的现实挑战 在智能健身、动作捕捉、虚拟试衣、人机交互等前沿应用中&#xff0c;人体骨骼关键点检测&#xff08;Human Pose Estimation&#xff09;已成为…

人体姿态估计部署指南:MediaPipe Pose的环境配置

人体姿态估计部署指南&#xff1a;MediaPipe Pose的环境配置 1. 引言 1.1 AI 人体骨骼关键点检测的工程价值 在智能健身、动作捕捉、虚拟试衣和人机交互等前沿应用中&#xff0c;人体姿态估计&#xff08;Human Pose Estimation&#xff09;已成为不可或缺的核心技术。其目标…

利用pjsip构建软电话(Softphone):零基础实战教程

从零开始用 pjsip 打造一个能打电话的软电话&#xff1a;实战全记录你有没有想过&#xff0c;自己动手写一个可以拨打电话的“软电话”&#xff1f;不是模拟器&#xff0c;不是调用系统 API&#xff0c;而是真正通过 SIP 协议注册到服务器、拨打号码、听到对方声音的那种。听起…

MediaPipe Pose技术揭秘:高精度骨骼检测背后的原理

MediaPipe Pose技术揭秘&#xff1a;高精度骨骼检测背后的原理 1. 引言&#xff1a;AI人体骨骼关键点检测的现实需求 在计算机视觉领域&#xff0c;人体姿态估计&#xff08;Human Pose Estimation&#xff09;是一项基础而关键的技术。它通过分析图像或视频中的人体结构&…

深入理解qthread中信号与槽的线程安全性

深入理解QThread中信号与槽的线程安全性&#xff1a;从机制到实战你有没有遇到过这样的场景&#xff1f;在子线程里处理完一堆数据&#xff0c;兴冲冲地调用label->setText("完成&#xff01;")&#xff0c;结果程序瞬间崩溃——没有明显报错&#xff0c;但调试器…

MediaPipe Pose完整部署:从零开始骨骼关键点检测

MediaPipe Pose完整部署&#xff1a;从零开始骨骼关键点检测 1. 引言&#xff1a;AI人体骨骼关键点检测的现实价值 随着计算机视觉技术的快速发展&#xff0c;人体姿态估计&#xff08;Human Pose Estimation&#xff09;已成为智能健身、动作捕捉、虚拟试衣、人机交互等场景…

手势识别避坑指南:用MediaPipe Hands镜像轻松实现21点定位

手势识别避坑指南&#xff1a;用MediaPipe Hands镜像轻松实现21点定位 在人机交互、智能控制和增强现实等前沿技术中&#xff0c;手势识别正逐渐成为下一代自然交互方式的核心。然而&#xff0c;许多开发者在尝试构建手势识别系统时&#xff0c;常常面临模型部署复杂、依赖环境…

React Native搭建环境新手必看常见错误汇总

React Native环境配置避坑指南&#xff1a;从零到运行&#xff0c;一次搞定 你是不是也经历过这样的场景&#xff1f;兴冲冲地打开终端&#xff0c;输入 npx react-native init MyAwesomeApp &#xff0c;结果等来的不是“Welcome to React Native”&#xff0c;而是一堆红色…

YOLOv8实战应用:智能安防监控系统快速搭建

YOLOv8实战应用&#xff1a;智能安防监控系统快速搭建 1. 引言&#xff1a;智能安防的视觉革命 随着城市化进程加快和公共安全需求提升&#xff0c;传统安防系统正面临从“看得见”向“看得懂”的转型压力。传统的视频监控依赖人工回看&#xff0c;效率低、响应慢&#xff0c…

毕业论文降AI神器推荐:从80%降到10%的秘密武器

毕业论文降AI神器推荐&#xff1a;从80%降到10%的秘密武器 “AI率80%&#xff0c;论文直接打回重写。” 这是我室友上周收到的噩耗。眼看答辩在即&#xff0c;毕业论文降AI成了宿舍里的热门话题。折腾了一周&#xff0c;终于帮他把**论文AI率从80%降到10%**以下&#xff0c;今…

MediaPipe Pose部署卡顿?极速CPU优化实战解决方案

MediaPipe Pose部署卡顿&#xff1f;极速CPU优化实战解决方案 1. 背景与痛点&#xff1a;AI人体骨骼关键点检测的落地挑战 随着AI视觉技术的发展&#xff0c;人体姿态估计&#xff08;Human Pose Estimation&#xff09;已成为智能健身、动作捕捉、虚拟试衣、安防监控等场景的…

libusb异步传输机制深度剖析与实践

libusb异步传输机制深度剖析与实践&#xff1a;从原理到工程落地在嵌入式系统、工业控制和高性能外设开发中&#xff0c;USB 已成为连接主机与设备的“标准语言”。无论是数据采集卡、图像传感器&#xff0c;还是音频接口&#xff0c;我们几乎都绕不开 USB 通信。而当面对高吞吐…

一键启动多语言翻译:HY-MT1.5-1.8B Docker部署全攻略

一键启动多语言翻译&#xff1a;HY-MT1.5-1.8B Docker部署全攻略 1. 引言 在全球化业务快速发展的背景下&#xff0c;实时、准确的多语言翻译能力已成为智能应用的核心基础设施。腾讯混元团队推出的 HY-MT1.5-1.8B 翻译模型&#xff0c;凭借其1.8亿参数量下卓越的翻译质量与极…

YOLOv8实战应用:智能仓储货物盘点系统快速搭建教程

YOLOv8实战应用&#xff1a;智能仓储货物盘点系统快速搭建教程 1. 引言&#xff1a;为什么需要智能仓储货物盘点&#xff1f; 在现代仓储物流体系中&#xff0c;人工盘点效率低、出错率高、成本高昂的问题长期存在。传统方式依赖员工逐件清点、手动记录&#xff0c;不仅耗时耗…