新闻详情

新闻详情

首页 / 资讯中心 / 详情

Array.from、Array.of、new Array 三种数组创建方法的核心区别与选型

发布时间:2026/10/2 3:58:30来源:尧图网络
Array.from、Array.of、new Array 三种数组创建方法的核心区别与选型
1. 引言三个方法都在创建数组行为却天差地别先说一个真实场景。之前在公司做代码评审有位同事写了一段new Array(3).map(() 0)本意是想要一个长度为 3、元素全是 0 的数组。结果运行之后数组还是空壳子map 回调根本没执行。这种问题说大不大但确实会让人在调试上浪费不少时间。后来我发现很多前端开发对Array.from()、Array.of()、new Array()这三个 API 的理解停留在“都是创建数组”的层面一旦往深了用各种隐蔽差异就全冒出来了。这三个方法确实经常被放在一起比较new Array()是 ES3 时代就存在的构造器Array.of()和Array.from()都是 ES6 新增的静态方法。但它们的定位完全不同——new Array()是构造函数Array.of()是修正参数行为的数组构造器Array.from()则是通用转换工具。如果你只是记结论那大概率会在某个边界场景里翻车如果你理解了各自的设计动机和内部规则就能在任何场景下快速选出正确写法。这篇文章我会结合实际踩坑经验把三个方法的区别拆开讲清楚包括稀疏数组、类数组对象、可迭代对象、映射函数这些绕不开的点最后再给一套可以直接照着选型的方法论。2. new Array()最老的构造器行为怪癖也最多2.1 单个数字参数你得到的不是元素而是数组长度先看最基本的行为差异。new Array(3)很多人直觉上认为它会生成[3]但它的真实结果是一个长度为 3、内部没有任何实际元素的数组。在控制台里通常显示为[empty × 3]Node 环境里也会显示[ 3 empty items ]。这里的“空位”和undefined完全不是一回事空位意味着这个索引上根本不存在属性而undefined是属性存在但值为undefined。可能你会觉得这有什么大不了的反正访问的时候不都是undefined吗错了。正因为索引位置没有属性很多数组方法在遍历时会直接跳过这些位置。比如new Array(3).map(x 1)结果依然是[empty × 3]map 回调一次都不会执行forEach、filter、reduce同样会跳过。我第一次踩这个坑是在写一个图表组件的数据初始化逻辑时想着先用new Array(12)生成 12 个格子然后再用 map 填数据结果图表死活渲染不出来控制台一打印才发现全是空壳。那为什么大家还这么爱用new Array(n)因为它和.fill()配合起来很好用。new Array(3).fill(0)能得到[0, 0, 0]这才是创建“固定长度密集数组”的经典写法。填完值之后map、forEach 就能正常遍历了。这里还要注意一个边界new Array(3.5)会直接抛RangeError: Invalid array length。数组长度必须是合法的、范围在 0 到 2^32 - 2 之间的整数。这个坑虽然不常见但偶尔会在动态计算长度的代码里冒出来。比如你根据某个除法结果取整时忘了Math.floor长度变成小数整个页面就直接崩了。2.2 多个参数行为和单参数完全不同new Array(1, 2, 3)的结果是[1, 2, 3]这个符合直觉。但这里的规则切换非常诡异只要参数数量大于等于 2所有参数都会被当作数组元素处理无论是不是数字。所以new Array(1, 2, 3)和new Array(1, 2, 3)行为是一致的——都是元素列表。真正特殊的只有“单个数字参数”这一种情况。这种“一个参数一个规则多个参数另一个规则”的设计是历史遗留。ES6 的Array.of()就是为了消除这个歧义而出现的。多参数模式下还有一个容易被忽略的问题如果你用new Array(5)创建一个稀疏数组然后直接赋值某个位置的元素比如arr[2] x中间依然会有空位。这种数组在JSON.stringify时会表现得很有趣——空位会被序列化为null。也就是说JSON.stringify(new Array(3))的结果是[null,null,null]这很容易让你误以为数组里真的有三个null其实原数组依然是空壳。我在处理接口数据回填时碰到过类似情况排错时一度以为是数据源问题最后才发现是空位序列化机制在作怪。3. Array.of()为补漏而生的参数构造器3.1 设计动机和基本规则Array.of()的设计目标非常明确消除new Array()的单参数歧义。只要是把参数传给Array.of()不管是一个还是多个不管是不是数字都会作为数组元素处理。对比一下就清楚了new Array(3); // [empty × 3] Array.of(3); // [3] Array.of(3, 4); // [3, 4] Array.of(3); // [3] new Array(3); // [3]单字符串参数会被当元素处理Array.of(1.5)得到[1.5]不会像new Array(1.5)那样抛 RangeError。Array.of()不传参数时得到空数组[]也和new Array()一致。从使用体验来看Array.of()本质上就是把一组参数“收纳”成一个数组。它的语义比new Array()更可预测所以如果你在一个函数里需要根据参数列表创建数组又不希望参数个数影响结果Array.of()就是最稳妥的选择。3.2 类数组场景的隐藏价值很多人以为Array.of()就是“用参数造个数组”没什么技术含量。但它在某些场景里比Array.prototype.slice.call(arguments)更干净。ES6 之后我们通常用展开运算符[...arguments]把类数组对象转成数组但在需要保留元素顺序、又不想引入额外语义时Array.of.apply(null, arrayLike)这种写法依然有其价值。当然现在更推荐直接Array.from()处理类数组对象这一点我在下一节展开。这里还有一个冷门但值得一提的机制Array.of()会使用this作为构造函数来创建最终数组。这意味着如果你给Array.of指定一个数组子类作为this结果就是那个子类的实例。class MyArray extends Array {} const result MyArray.of(1, 2, 3); console.log(result instanceof MyArray); // true这个特性在日常业务代码里用到得很少但它解释了为什么在规范层面Array.of()和new Array()不能被简单地互相替代。如果你需要写通用底层库或工具函数这一点是值得留意的。4. Array.from()真正的“全能转换器”4.1 类数组对象有 length 就能变成数组Array.from()的第一大能力是把类数组对象转成真正的数组。类数组对象指的是“有length属性、索引从 0 开始可以通过下标访问元素”的对象。最典型的例子是arguments对象和 DOM 查询结果NodeList。早期要把这些对象转成数组主流写法是Array.prototype.slice.call(arguments)或者循环 push。现在用Array.from()一行搞定function test() { const args Array.from(arguments); console.log(args); // [1, 2, 3] } test(1, 2, 3);很多人对这个功能的理解止步于此但实际上Array.from()对类数组对象的处理有一个关键规则它会先读取对象的length然后依次访问0到length - 1这些索引上的属性。就算某些索引上没有属性也会在结果数组里补上undefined。这一点和稀疏数组的行为差异非常大。举个例子如果传入一个稀疏数组Array.from()的结果是密集数组空位全部被填充为undefinedconst sparse [1, , 3]; // 索引 1 是空位 const dense Array.from(sparse); console.log(1 in dense); // true console.log(dense[1]); // undefined这在处理外部数据时特别有用。有时候你从某个旧接口收到一个坑坑洼洼的数组直接用Array.from()过一遍空位就变成了普通的undefined后面遍历时逻辑更可控。4.2 第二参数 mapFn转换的同时顺便做映射Array.from()的结构是Array.from(arrayLike, mapFn, thisArg)。第二个参数是一个映射函数作用类似数组的map()但实现机制不同它是边取元素边映射不会再创建一个中间数组。第三个参数thisArg可以指定映射函数内部this的指向。这个特性让Array.from()在生成序列时非常好用。比如创建一个 0 到 9 的数字数组const nums Array.from({ length: 10 }, (_, i) i); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]这个写法替代了经典的三段式new Array(10).fill(0).map((_, i) i)。后者要先创建数组、填充、再映射多走了一步前者直接用长度对象配合映射函数一次性搞定可读性也更好。映射函数还适合在转换过程中做格式整理。比如拿到的类数组对象里全是字符串数字你想直接转成数字数组const arrLike { 0: 10, 1: 20, 2: 30, length: 3 }; const nums Array.from(arrLike, Number); // [10, 20, 30]注意这里直接把Number作为映射函数传入简洁又不失可读性。实际工作中我经常用类似手法把接口返回的数据对象“拍”成数组省去多次循环。4.3 可迭代对象字符串、Set、Map、生成器Array.from()的另一大能力是处理可迭代对象。只要对象具有[Symbol.iterator]方法Array.from()就能把它完整展开成数组。字符串是最常见的例子。Array.from(hello)能直接把字符串按字符拆开。但如果你用展开运算符[...str]其实也能做到。两者的区别主要体现在处理 Unicode 字符时Array.from()和展开运算符都会按迭代器走也就是按 Unicode 码点拆分而不是按 UTF-16 编码单元拆。比如对于包含代理对字符的字符串split()会把字符劈成两半而Array.from()会保持完整。const str Abfe; console.log(str.split()); // [A, b, 乱掉的字符..., f, e] console.log(Array.from(str)); // [A, b, 完整字符, f, e]虽然这里我没有给出具体乱码字符但你可以放心处理多字节字符时优先用Array.from()不要用split()。Set和Map也很典型。Array.from(new Set([1, 2, 3]))能把 Set 转成数组。Array.from(map)会得到键值对数组的数组。这个需求用展开运算符也能实现但Array.from()在作为函数参数传递时更方便因为它本身就是一个独立的函数可以灵活传给其他高阶函数。生成器对象同样支持。以前我写数据分页工具时会用一个生成器按批次产出数据然后用Array.from()一次性收集全部结果function* generate() { yield 1; yield 2; yield 3; } const arr Array.from(generate()); // [1, 2, 3]Array.from()会自动遍历迭代器直到结束。这也是它区别于new Array()和Array.of()的显著特征——后面两者根本不接受迭代器参数传进去也只是当成单个元素。4.4 对数组长度的特殊处理Array.from()还有个容易被忽略的细节它以length为准来遍历而不是以对象实际拥有的属性数量为准。这意味着什么意味着一个看起来“空无一物”的对象只要长度大就会生成一个很长的数组。const fake { length: 3 }; const result Array.from(fake); // [undefined, undefined, undefined]这一点我在前面提过但它值得单独强调Array.from()不检查对象里是否真的有对应索引而是“按”长度逐一访问。这正是它能用来快速生成数字序列的原理。反过来说如果你传入一个 length 非常大的对象性能上会花很长时间因为每个索引都会被访问一次。5. 实战选型一张表和三句口诀5.1 核心差异对照表把三个方法放在一起横向看差异会清晰很多维度new Array()Array.of()Array.from()本质构造函数静态构造方法静态转换方法单个数字参数当作长度生成稀疏数组当作元素当作类数组处理无实际意义多个参数全部当作元素全部当作元素参数被当作类数组对象通常不用来传列表支持类数组对象不支持不支持支持按 length 遍历支持可迭代对象不支持不支持支持自动展开迭代器支持映射函数不支持不支持支持第二参数空位处理保留空位无空位概念把空位填充为 undefined子类定制通过 new 绑定通过 this 绑定通过 this 绑定典型用途创建指定长度数组后 fill把少量参数收纳为数组转换类数组/可迭代对象并映射这张表涵盖了大部分差异但实际选型时我建议你记住三句口诀已知固定元素数量不多优先用数组字面量[...]或者用Array.of()。想创建一个指定长度的数组后续再用.fill()或.map()填值用new Array(n)。手头有类数组对象、可迭代对象或者需要边转换边映射直接用Array.from()。5.2 常见模式的具体替换很多读者问过我既然Array.from()功能这么强是不是以后就不需要new Array和Array.of了不是。它们各自有不可替代的使用场景。生成数字序列优先Array.fromArray.from({ length: 5 }, (_, i) i 1); // [1, 2, 3, 4, 5]创建定长全0数组优先new Array(n).fill(0)const arr new Array(5).fill(0); // [0, 0, 0, 0, 0]fill之后的数组是密集的每个索引都有真实属性后续一切数组方法都能正常使用。把一组参数变成数组用Array.offunction collect(a, b, c) { return Array.of(a, b, c); }如果这里用new Array(a, b, c)只要传入了单个数字参数行为就会跑偏。比如collect(3)用new Array返回的是[empty × 3]而Array.of返回的是[3]。使用 API 时不确定性是最大的敌人Array.of正是为此而生。5.3 引用陷阱fill 和 Array.from 的差异补充一个实战里很容易踩的坑new Array(3).fill({})和Array.from({ length: 3 }, () ({}))看起来都生成了三个对象元素但它们有本质区别。fill()是往每个位置填充“同一个引用”。也就是说生成的三个元素是同一个对象的三份引用不是三个独立对象。如果你修改其中一个另外两个也会跟着变。而Array.from()的映射函数会为每个元素执行一次每次返回一个新对象所以是三个独立对象。const a new Array(3).fill({ count: 0 }); a[0].count; console.log(a[1].count); // 1被连带修改了 const b Array.from({ length: 3 }, () ({ count: 0 })); b[0].count; console.log(b[1].count); // 0互不影响这个差异在处理表格数据、批量初始化复杂对象时非常关键。你要心里有数什么时候需要共享对象什么时候需要独立对象。6. 常见误区与经验笔记6.1 误把 Array.from 当数组构造器一个高频误区是想用Array.from(3)生成[3]或长度为 3 的数组结果完全不对。因为Array.from()接受的是类数组对象或可迭代对象单个数字既不是可迭代对象也没有length属性最终会生成一个空数组[]。Array.from(3); // [] Array.of(3); // [3] new Array(3); // [empty × 3]如果你脑子里没有牢固的“转换器”定位很容易在这种边界上翻车。我的习惯是凡是要处理数字参数本身一律用Array.of或字面量凡是要处理“有长度的东西”才考虑Array.from。另一个与之相关的误区是把Array.from({ length: 3 }, () 0)和new Array(3).fill(0)等同看待。虽然结果都是[0, 0, 0]但实现路径不同性能语义也不同。new Array(3)先创建稀疏数组再逐个填值Array.from则通过 length 遍历生成密集数组。从可读性看前者更直白后者更函数式。两者选哪个更多看团队风格不必纠结。6.2 排查空位问题的思路如果你在代码里发现数组遍历结果不符合预期第一步就应该检查数组是不是稀疏的也就是是否存在空位。常见判断方法有两个。第一种用in运算符const arr new Array(3); console.log(0 in arr); // false索引 0 没有属性第二种直接看控制台输出。如果是[empty × 3]而不是[undefined × 3]说明是稀疏数组。如果发现有空位最快的处理方式是用Array.from()过一遍把空位变成undefined然后再继续操作。或者直接用Array.from()作为遍历前的第一步一步到位。我早期排查过一个问题一段渲染逻辑里用arr.forEach给每个格子绘制图形但是数组是用new Array(n)创建的没经过fill结果页面上一片空白。这类问题不报错、不崩溃最容易让人怀疑是布局和样式的问题浪费大量时间。排查数组空位应该成为你处理动态数据时的基本反射。6.3 性能笔记别在小数组上过度优化关于性能先说结论业务代码里这三个方法的性能差距通常可以忽略不计除非你在处理超大数组。我用new Array(n).fill()、Array.from({ length: n })跑过简单基准测试new Array(n).fill()往往更快因为引擎对数组预分配长度的优化很成熟。而Array.from()因为需要处理映射函数和通用遍历逻辑开销会略高。但这个差距在十万级以下基本感知不到。更重要的反而是语义正确性。不要为了节省一次映射的消耗把本来用Array.from能写清楚的逻辑拆成new Array().map()代码可读性会明显下降。性能优化要让位于意图清晰尤其是在数组创建这种高频但规模不一定大的操作上。还有一点想特别提醒Array.from()第二参数映射函数里尽量别写复杂的副作用逻辑。它会按索引顺序执行如果你在映射过程中又修改了原数组结果会非常难调试。记得保持映射函数的纯函数风格用起来会省心很多。6.4 冷门但有用的细节数组最大合法长度是2^32 - 2new Array(4294967296)会抛 RangeError。Array.of(4294967296)则完全没问题因为它只是把数字当作元素。Array.from()会使用this作为构造函数。如果this不是一个可调用对象它回退到普通数组。这个机制在自定义数组子类里很重要写通用库时要留意。Array.of()也一样受this影响。但它不接受类数组对象如果你需要对类数组对象做子类转换用Array.from()更合适。如果你在浏览器里拿到的是HTMLCollection而不是NodeListArray.from()同样能处理因为它们都有length属性和索引访问能力。在我自己的项目实践中最常用的组合是用Array.from({ length: n }, 映射函数)生成索引数组用Array.of()在可变参数函数里收纳参数用new Array(n).fill(value)做定长初始化。这三个场景几乎覆盖了日常开发里 90% 的数组创建需求。搞清楚它们背后的规则之后你写代码时会多一层确定性排查问题时也不会再被“看起来一样的数组”骗到。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

OfficeCLI Morph-PPT 风格实战:用 Spectral Grid 打造高能科技发布会幻灯片 2026/10/2 8:16:06

OfficeCLI Morph-PPT 风格实战:用 Spectral Grid 打造高能科技发布会幻灯片

CLIAI 应用MCP 服务 【免费下载链接】OfficeCLI OfficeCLI is the first and best Office suite purpose-built for AI agents to read, edit, and automate Word, Excel, and PowerPoint files. Free, open-source, single binary, no Office installation required. 项目地址…

阅读更多 →
Selenium Grid 4.48.0 发布记录解析:Chrome for Testing 129.0.6668.100 镜像标签生成全流程 2026/10/2 8:16:05

Selenium Grid 4.48.0 发布记录解析:Chrome for Testing 129.0.6668.100 镜像标签生成全流程

测试后端云原生容器编排可观测性 【免费下载链接】docker-selenium Provides a simple way to run Selenium Grid with Chrome, Firefox, and Edge using Container Platform, making it easier to perform browser automation at scale 项目地址: https://gitcode.…

阅读更多 →
PX4 SetpointConfigReply 消息详解:外部模式设定点配置的请求-应答机制 2026/10/2 8:15:59

PX4 SetpointConfigReply 消息详解:外部模式设定点配置的请求-应答机制

嵌入式物联网机器人自动驾驶智能硬件 【免费下载链接】PX4-Autopilot PX4 Autopilot Software 项目地址: https://gitcode.com/gh_mirrors/px/PX4-Autopilot 点击查看 免费下载 导读 SetpointConfigReply 是 PX4 飞控中一组 uORB 消息 setpoint_config / setpoint…

阅读更多 →
I/O 多路复用全解:从 Socket 阻塞模型到 select/poll/epoll 与 C10K 实战(CS-Base 图解系统) 2026/10/2 8:15:59

I/O 多路复用全解:从 Socket 阻塞模型到 select/poll/epoll 与 C10K 实战(CS-Base 图解系统)

文档教程知识库 【免费下载链接】CS-Base 图解计算机网络、操作系统、计算机组成、数据库,共 1000 张图 50 万字,破除晦涩难懂的计算机基础知识,让天下没有难懂的八股文!🚀 在线阅读:https://xiaolincodin…

阅读更多 →
大模型降价潮下的Claude Code配置与智能体权限实战指南 2026/10/2 8:15:59

大模型降价潮下的Claude Code配置与智能体权限实战指南

1. 这波模型降价背后的真实逻辑1.1 从"价格砍半"说起:为什么大模型突然集体降价这两天圈子里讨论最多的就是几个头部模型的价格调整。Opus 5.5 在登顶能力榜之后,价格直接砍了 40%,GPT-6 的 Sol 和 Luna 两个版本几乎腰斩&#xff…

阅读更多 →
OpenClaw 接入 Chrome 实战:从 WSL2 到 CDP 的浏览器自动化部署指南 2026/10/2 8:15:59

OpenClaw 接入 Chrome 实战:从 WSL2 到 CDP 的浏览器自动化部署指南

OpenClaw 接入 Chrome 这件事,最近在 AI 自动化圈子里讨论度明显上来了。简单说,OpenClaw 是一个开源的、可以部署在自己机器上的个人 AI 助手框架,它能记住上下文、调用工具、执行任务,而把 Chrome 浏览器接进去之后,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉