JS中from方法将类数组转数组的方法
`Array.from()`是 JavaScript 中一个强大的工具,可以将类数组对象或可迭代对象转换为真正的数组,从而可以使用数组的各种方法。本文详细介绍了`Array.from()`的用法,包括处理 NodeList、arguments 对象和自定义类数组对象。此外,还深入探讨了如何结合映射函数在转换过程中同步处理元素,以及`thisArg`参数的使用。通过实例对比`Array.from()`与其他转换方法(如展开运算符和`slice.call`)的区别,强调了其在处理不可迭代类数组和支持映射方面的优势。同时,提醒开发者注意浅拷贝带来的引用共享问题,避免与`Array.of()`混淆,从而更高效地运用`Array.from()`处理各种数据结构。
Array.from() 可将类数组或可迭代对象转换为真数组,1. 它通过识别对象的 length 属性和索引或 Symbol.iterator 接口实现转换;2. 常用于处理 NodeList、arguments 或自定义类数组对象;3. 支持第二个参数映射函数,实现转换时同步处理元素;4. 与 [...spread] 相比能处理不可迭代的类数组,与 slice.call 相比语法更清晰且支持映射;5. 可生成指定长度数组、转换 Set/Map、结合 thisArg 使用;6. 注意仅适用于类数组或可迭代对象,对普通对象返回空数组,且为浅拷贝,需警惕引用共享问题,同时不可与 Array.of() 混淆,后者用于创建新数组而非转换结构。
Array.from()
是 JavaScript 中一个非常实用的方法,它能将类数组对象或可迭代对象(Iterable)高效地转换成一个真正的数组实例。简单来说,当你拿到一个看起来像数组但又不能直接调用数组方法(比如 map
、filter
)的对象时,Array.from()
就是你的救星,它会创建一个全新的、浅拷贝的数组。
解决方案
要用 Array.from()
将类数组对象转为真数组,核心在于理解它如何识别“类数组”或“可迭代”对象。一个对象只要具备 length
属性和可访问的索引(比如 obj[0]
, obj[1]
),或者它是一个可迭代对象(实现了 Symbol.iterator
接口),Array.from()
就能对其进行操作。
最常见的场景就是处理 DOM NodeList
、函数内部的 arguments
对象,或者你自己构造的带有 length
属性的对象。
基本用法示例:
转换
NodeList
(DOM元素集合): 当你通过document.querySelectorAll()
获取到一组元素时,得到的是一个NodeList
,它不是一个真正的数组。const divs = document.querySelectorAll('div'); // 这是一个NodeList const divArray = Array.from(divs); // 现在divArray就是一个真数组了 // 可以在divArray上使用所有数组方法 divArray.forEach(div => console.log(div.textContent));
转换
arguments
对象: 在函数内部,arguments
是一个类数组对象,包含了函数调用时传入的所有参数。function sumAll() { // arguments是一个类数组对象 const argsArray = Array.from(arguments); return argsArray.reduce((acc, val) => acc + val, 0); } console.log(sumAll(1, 2, 3, 4)); // 输出 10
转换自定义的类数组对象: 只要你的对象有
length
属性和索引元素,Array.from()
就能处理。const myCollection = { 0: 'apple', 1: 'banana', 2: 'orange', length: 3 }; const fruits = Array.from(myCollection); // ['apple', 'banana', 'orange'] console.log(fruits instanceof Array); // true
结合映射函数进行转换和处理:
Array.from()
的第二个参数是一个映射函数(mapFn
),这让它在转换的同时还能对每个元素进行处理。这功能非常强大,省去了先转换再map
的步骤。const numbers = Array.from({ length: 5 }, (_, i) => i * 2); // 生成 [0, 2, 4, 6, 8] // 第一个参数是 { length: 5 },一个简单的类数组对象 // 第二个参数是映射函数,_ 表示当前元素(这里是 undefined),i 是索引 const stringLengths = Array.from('hello', char => char.charCodeAt(0)); // 将字符串(可迭代)转换为字符的ASCII码数组 [104, 101, 108, 108, 111]
为什么我们需要将类数组对象转换为真数组?
这问题问得好,因为这确实是 JavaScript 开发中一个很常见的痛点。我们之所以执着于把类数组对象变成“真”数组,最核心的原因就是方法缺失。你想想,当你拿到一个 NodeList
或者 arguments
对象时,你没法直接调用 map
、filter
、reduce
甚至是 forEach
(虽然 NodeList
和 arguments
有时会有 forEach
,但那不是 Array.prototype.forEach
,行为上可能存在细微差异或兼容性问题),更别提 sort
、slice
、splice
这些功能强大的数组方法了。
这就好像你买了一辆车,它看起来像车,开起来也像车,但它没有方向盘、没有刹车、没有油门,你只能看着它。类数组对象就是这样,它们有 length
属性,有索引,让你觉得它们是数组,但它们没有继承 Array.prototype
上的那些好用方法。
所以,转换为真数组,就是为了解锁这些原生数组方法,让数据处理变得更灵活、更符合直觉。一旦它们变成了真数组,你就可以用链式调用 (.map(...).filter(...).reduce(...)
) 来进行复杂的数据转换和聚合,代码也会变得更简洁、更具表达力。这在我看来,是提高开发效率和代码可读性的关键一步。
Array.from() 与其他转换方法的区别在哪里?
在 Array.from()
出现之前,我们处理类数组对象主要有两种方式,现在有了 Array.from()
和 ES6 的展开运算符(Spread Syntax),选择就更多了。它们各有特点,理解这些差异能帮助你选择最适合的工具。
[].slice.call(arrayLikeObject)
(经典方法): 这是 ES6 之前最常用的转换技巧。它的原理是“借用”Array.prototype.slice
方法。slice
方法在没有参数时,会返回原数组的一个浅拷贝。通过call
方法,我们将this
上下文指向类数组对象,从而让slice
像处理数组一样处理它。const divs = document.querySelectorAll('div'); const divArrayOld = [].slice.call(divs);
区别:
- 简洁性:
Array.from()
更直观,意图更明确。[].slice.call()
看起来有点像“黑魔法”,需要理解call
的作用和slice
的行为。 - 功能:
Array.from()
可以直接传入映射函数,实现转换和映射一步到位。slice.call
只能做转换,如果需要映射,还得再跟一个map
方法。 - 兼容性:
Array.from()
是 ES6 新增的,IE 浏览器需要 Polyfill。slice.call
兼容性更好。 - 可迭代对象:
slice.call
只能处理类数组对象(有length
和索引),而Array.from()
还能处理任何可迭代对象(如Set
、Map
、字符串),这是它一个非常大的优势。
- 简洁性:
展开运算符 (
...
Spread Syntax): 如果类数组对象是可迭代的(比如NodeList
、字符串、Set
、Map
),你也可以使用展开运算符将其转换为数组。const divs = document.querySelectorAll('div'); const divArraySpread = [...divs]; const mySet = new Set([1, 2, 3]); const setArray = [...mySet]; // [1, 2, 3]
区别:
- 简洁性: 展开运算符无疑是最简洁的语法,非常直观。
- 功能: 同样,展开运算符只能做转换,不能像
Array.from()
那样直接集成映射功能。 - 限制: 展开运算符只能用于可迭代对象。对于只有
length
属性和索引但不可迭代的自定义类数组对象(例如上面myCollection
的例子,除非你手动给它添加Symbol.iterator
),展开运算符是无效的。而Array.from()
依然可以处理。 - 性能: 在大多数现代 JavaScript 引擎中,这些方法的性能差异通常可以忽略不计,不应成为选择的主要依据,除非你处理极其庞大的数据集。
总结一下:
Array.from()
是最通用和功能最丰富的选择,它能处理类数组和可迭代对象,并支持一步到位的数据转换。- 展开运算符最简洁,但仅限于可迭代对象。
[].slice.call()
是老派但可靠的方法,主要用于兼容性要求高的类数组转换。
我个人在写新代码时,会优先考虑 Array.from()
,因为它功能全面且语义清晰。如果只是简单的可迭代对象转换,展开运算符的简洁性也很吸引人。
Array.from() 的进阶用法和常见误区有哪些?
Array.from()
确实是个多面手,但用起来也有些地方需要注意,避免踩坑。
进阶用法:
快速生成特定长度和内容的数组: 这个用法非常巧妙,你不需要一个实际的“类数组对象”,只需要一个带有
length
属性的对象,就能利用Array.from()
和它的映射函数来生成数组。这比new Array(length).fill(value)
结合map
更加简洁。// 生成一个包含1到10数字的数组 const numbers = Array.from({ length: 10 }, (_, i) => i + 1); console.log(numbers); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 生成一个包含指定字符重复次数的数组 const repeatedChars = Array.from({ length: 5 }, () => 'X'); console.log(repeatedChars); // ['X', 'X', 'X', 'X', 'X']
这里
_
(下划线) 是一个常见的约定,表示我们不关心映射函数接收到的第一个参数(即Array.from
从{ length: N }
中取出的undefined
值),只关心索引i
。处理
Set
和Map
对象:Set
和Map
都是可迭代对象,Array.from()
可以直接将它们转换为数组。这在需要对Set
或Map
的内容进行数组操作时非常有用。const uniqueIds = new Set([101, 105, 103, 101]); const idArray = Array.from(uniqueIds); // [101, 105, 103] const userMap = new Map([['id', 1], ['name', 'Alice']]); const mapEntries = Array.from(userMap); // [['id', 1], ['name', 'Alice']] const mapKeys = Array.from(userMap.keys()); // ['id', 'name'] const mapValues = Array.from(userMap.values()); // [1, 'Alice']
使用
thisArg
参数:Array.from()
的第三个参数是thisArg
,它允许你为映射函数指定this
的值。这在映射函数是一个对象方法时特别有用。const converter = { prefix: 'item-', convert(value, index) { return this.prefix + value + '-' + index; } }; const data = [1, 2, 3]; const convertedData = Array.from(data, converter.convert, converter); console.log(convertedData); // ["item-1-0", "item-2-1", "item-3-2"] // 如果没有第三个参数 converter,converter.convert 内部的 this 会是 undefined
常见误区:
不是所有对象都能被转换:
Array.from()
并不是万能的。它要求传入的对象要么是“类数组”(有length
属性和索引),要么是“可迭代对象”(实现了Symbol.iterator
接口)。如果你传入一个普通的对象,它既没有length
属性也没有迭代器,那么Array.from()
会返回一个空数组。const plainObject = { a: 1, b: 2 }; const result = Array.from(plainObject); console.log(result); // [] (因为 plainObject 既不是类数组也不是可迭代对象)
浅拷贝的陷阱: 和许多其他数组创建方法一样,
Array.from()
执行的是浅拷贝。这意味着如果原始对象或可迭代对象中包含引用类型(如其他对象或数组),那么新数组中存储的将是这些引用,而不是它们的副本。修改新数组中的引用类型元素,会影响到原始数据。const originalArray = [{ id: 1 }, { id: 2 }]; const newArray = Array.from(originalArray); newArray[0].id = 99; console.log(originalArray[0].id); // 99 (原始数组的元素也被修改了)
如果需要深拷贝,你需要自己实现一个深拷贝逻辑,或者使用像
JSON.parse(JSON.stringify(obj))
这样的方式(但它有局限性,比如不能处理函数、undefined
、Symbol
等)。与
Array.of()
的混淆:Array.from()
和Array.of()
名字有点像,但功能完全不同。Array.of()
是用来根据传入的参数创建一个新的数组实例,它解决了new Array()
在传入单个数字参数时的歧义问题。// Array.from() 转换现有结构 Array.from('abc'); // ['a', 'b', 'c'] // Array.of() 根据参数创建新数组 Array.of(1, 2, 3); // [1, 2, 3] Array.of(7); // [7] (而 new Array(7) 会创建一个长度为7的空数组)
记住,
Array.from()
是“从...来”,Array.of()
是“创建...的”。
掌握这些进阶用法和避开常见误区,能让你更自如、更高效地运用 Array.from()
处理 JavaScript 中的各种数据结构。
终于介绍完啦!小伙伴们,这篇关于《JS中from方法将类数组转数组的方法》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

- 上一篇
- 图片加alt文本的四大原因:提升可访问性、优化SEO、增强体验、符合规范

- 下一篇
- DIV中SELECT被截断解决方法
-
- 文章 · 前端 | 31秒前 |
- HTML中标签的正确用法与SEO优化
- 198浏览 收藏
-
- 文章 · 前端 | 6分钟前 |
- JavaScript事件循环详解与原理分析
- 330浏览 收藏
-
- 文章 · 前端 | 6分钟前 |
- JavaScript中getDay方法使用详解
- 240浏览 收藏
-
- 文章 · 前端 | 10分钟前 |
- JavaScript数组懒加载技巧分享
- 404浏览 收藏
-
- 文章 · 前端 | 14分钟前 | 画中画 ::picture-in-picture-button document.pictureInPictureEnabled requestPictureInPicture 画中画事件
- HTML画中画按钮样式与伪类应用解析
- 182浏览 收藏
-
- 文章 · 前端 | 17分钟前 |
- 事件循环调试技巧与问题解决方法
- 490浏览 收藏
-
- 文章 · 前端 | 21分钟前 | html 路径 Favicon 图标格式 linkrel="icon"
- HTML设置网站图标方法详解
- 456浏览 收藏
-
- 文章 · 前端 | 22分钟前 |
- JS发送POST请求的几种方式
- 479浏览 收藏
-
- 文章 · 前端 | 23分钟前 |
- JavaScriptObject.assign详解与使用方法
- 427浏览 收藏
-
- 文章 · 前端 | 26分钟前 | JavaScript 随机数 Math.random() crypto.getRandomValues() 伪随机
- JS随机数生成方法全解析
- 451浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 511次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 498次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 千音漫语
- 千音漫语,北京熠声科技倾力打造的智能声音创作助手,提供AI配音、音视频翻译、语音识别、声音克隆等强大功能,助力有声书制作、视频创作、教育培训等领域,官网:https://qianyin123.com
- 173次使用
-
- MiniWork
- MiniWork是一款智能高效的AI工具平台,专为提升工作与学习效率而设计。整合文本处理、图像生成、营销策划及运营管理等多元AI工具,提供精准智能解决方案,让复杂工作简单高效。
- 170次使用
-
- NoCode
- NoCode (nocode.cn)是领先的无代码开发平台,通过拖放、AI对话等简单操作,助您快速创建各类应用、网站与管理系统。无需编程知识,轻松实现个人生活、商业经营、企业管理多场景需求,大幅降低开发门槛,高效低成本。
- 172次使用
-
- 达医智影
- 达医智影,阿里巴巴达摩院医疗AI创新力作。全球率先利用平扫CT实现“一扫多筛”,仅一次CT扫描即可高效识别多种癌症、急症及慢病,为疾病早期发现提供智能、精准的AI影像早筛解决方案。
- 179次使用
-
- 智慧芽Eureka
- 智慧芽Eureka,专为技术创新打造的AI Agent平台。深度理解专利、研发、生物医药、材料、科创等复杂场景,通过专家级AI Agent精准执行任务,智能化工作流解放70%生产力,让您专注核心创新。
- 192次使用
-
- 优化用户界面体验的秘密武器:CSS开发项目经验大揭秘
- 2023-11-03 501浏览
-
- 使用微信小程序实现图片轮播特效
- 2023-11-21 501浏览
-
- 解析sessionStorage的存储能力与限制
- 2024-01-11 501浏览
-
- 探索冒泡活动对于团队合作的推动力
- 2024-01-13 501浏览
-
- UI设计中为何选择绝对定位的智慧之道
- 2024-02-03 501浏览