前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Array.from 可迭代对象与类数组参数
JavaScript数组与集合

Array.from 能转换类数组,为什么数组展开有时却会报错?

Array.from 先看参数有没有 Symbol.iterator,有就按迭代器取值;没有就退回类数组模式,读 length 再按下标 0、1、2 取。数组展开 [...x] 只走迭代器这一条路,像 { 0: "a", length: 1 } 这种只有下标和长度的对象,展开时就会抛 TypeError。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数组与集合#异步编程
先看核心答案读代码示例
理解线索

两种能被转成数组的输入

  1. 可迭代对象有 Symbol.iterator 方法,比如数组、字符串、Set、Map、NodeList
  2. 类数组有 length 和数字下标,但没有迭代器,比如 { 0: "a", length: 1 }
  3. Array.from 的选择有迭代器走迭代器,没有才按 length 读下标

arguments 和 NodeList 在现代浏览器里既是类数组又可迭代,所以两种写法都能用。真正只能用 Array.from 的,通常是自己拼出来的对象或者老接口返回的结果。

核心回答

先记住这个答案

Array.from 接受两类输入。如果参数有 Symbol.iterator 方法,它就按迭代器一个个取值;如果没有,它就把参数当类数组,读出 length,再按 0 到 length - 1 的下标逐个取值。数组展开 [...x] 只认迭代器,只有 length 和下标的对象不可迭代,展开时会抛 TypeError。两种条件都满足时,Array.from 优先用迭代器,结果不一定等于那些下标属性。它创建的是新数组,但只是浅拷贝,缺失的下标会变成真实的 undefined。

  • Array.from 支持可迭代对象和类数组两种输入
  • 数组展开只支持可迭代对象,类数组会报错
  • 两者都有时,Array.from 优先用迭代器
  • 类数组里缺失的下标会变成 undefined

同一个对象,两种写法

类数组指有 length 属性、并且用数字作为键的对象,长得像数组,但原型上没有数组方法,也不一定能迭代。

类数组、Set 和生成序列JavaScript
const likeArr = { 0: 'a', 1: 'b', length: 2 } // 只有下标和 length
console.log(JSON.stringify(Array.from(likeArr)))

try {
  console.log([...likeArr])
} catch (e) {
  console.log(e.name) // 普通对象没有迭代器
}

console.log(JSON.stringify(Array.from(new Set([1, 1, 2])))) // 可迭代对象
console.log(JSON.stringify(Array.from({ length: 3 }, (_, i) => i * 2))) // 第二个参数是映射函数
查看输出与解释
["a","b"]
TypeError
[1,2]
[0,2,4]

likeArr 没有 Symbol.iterator,展开语法不知道怎么逐个取值,只能报错。Array.from 发现没有迭代器,就退回到按 length 读下标的模式,所以能转换成功。 最后一行是 Array.from 很常用的一个技巧:{ length: 3 } 是一个只有长度的类数组,配合第二个参数 mapFn,就能直接生成 [0, 2, 4] 这样的序列。mapFn 在创建过程中对每一项调用,不会先生成中间数组。

迭代器优先,缺失下标变 undefined

如果一个对象既有迭代器又有 length 和下标,Array.from 会忽略下标,只看迭代器产出了什么。

两种条件都满足时,以及缺了下标时JavaScript
const both = {
  0: 'index', length: 1,
  *[Symbol.iterator]() { yield 'iter1'; yield 'iter2' }
}
console.log(JSON.stringify(Array.from(both))) // 走迭代器,下标被忽略

const holes = Array.from({ length: 2, 1: 'x' }) // 下标 0 不存在
console.log(0 in holes, holes[0], holes[1])
查看输出与解释
["iter1","iter2"]
true undefined x

第一段结果里完全没有 'index',而且长度是 2 而不是 length 声明的 1。所以说 Array.from 的结果「不一定等于索引属性」。 第二段里,原对象下标 0 根本不存在,Array.from 读到 undefined 后照样写进了新数组,0 in holes 是 true。也就是说原来的「空位」变成了「有值,值是 undefined」。之后调用 forEach、map 时,这一项会被访问到,而原来的空位是会被跳过的。

回答前,多想一步

容易答错的地方

以为 Array.from 是深拷贝
它只创建一个新的外层数组。Array.from([{ n: 1 }]) 里的对象还是原来那个,修改它会影响原数组。
用 Array.from 转普通对象的键值
Array.from({ a: 1, b: 2 }) 得到空数组,因为这个对象既没有迭代器,length 也是 undefined,按 0 处理。要把普通对象转成数组,用 Object.keys、Object.values 或 Object.entries。
以为能直接转换异步迭代器
Array.from 只处理同步迭代器。传入异步生成器,它找不到 Symbol.iterator,会退回类数组模式,最后得到一个空数组。异步场景用 for await...of 收集,较新的环境也提供了 Array.fromAsync。
试着用自己的话回答

面试官还会怎么问?

Array.from(str) 和 str.split('') 有什么区别?

字符串的迭代器按 Unicode 码点遍历,split('') 按 UTF-16 编码单元切。对于 emoji 这类占两个编码单元的字符,Array.from('👍a') 得到 2 项,'👍a'.split('') 得到 3 项,其中两项是乱码的半个字符。

Array.from 和 Array.prototype.slice.call 都能转类数组,区别是什么?

slice.call(arguments) 是 ES5 时代的写法,只按 length 和下标读取,不认迭代器,而且会保留空位。Array.from 两种都认,缺失下标变成 undefined,还能顺带传 mapFn。新代码直接用 Array.from。

传入 null 或 undefined 会怎样?

抛 TypeError,因为它们没法转成对象。传入数字、布尔值不会报错,它们被转成包装对象,没有迭代器,length 也是 undefined,结果是空数组。

从一道题,走向一组知识

把知识连起来

数组与集合

数组展开为什么能复制数组和 Set,它背后到底读取了什么?

展开语法完全依赖迭代器协议,这题讲的是它为什么对类数组无效,那题讲它怎么消费迭代器。

数组与集合

什么是类数组对象?arguments 和真数组有什么区别,怎么转换?

arguments 是最常见的类数组,转成数组时 Array.from 和展开都能用。

数组与集合

稀疏数组的空位和 undefined 有什么区别,为什么 Array(n).map 不执行?

Array.from 会把缺失的下标变成真实的 undefined,理解空位后就知道这有什么影响。

参考资料

  • MDN:Array.from
  • MDN:展开语法

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 同一个对象,两种写法
  3. 迭代器优先,缺失下标变 undefined
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑