扩展运算符依赖对象的迭代器协议,先调用[Symbol.iterator]()获取迭代器,再循环调用next()直至done为true,收集value构成新数组或传参;仅原生可迭代对象及自定义实现迭代器的对象可用,普通对象等不可用。

扩展运算符(...)在 JavaScript 中底层依赖对象的迭代器协议,即调用对象的 [Symbol.iterator]() 方法获取一个迭代器,再反复调用该迭代器的 next() 方法,直到返回 { done: true }。
扩展运算符触发迭代器的完整流程
当你写 const arr2 = [...arr1] 或 func(...args) 时,引擎实际执行以下步骤:
- 检查被展开的对象是否具有
[Symbol.iterator]方法(可调用且返回迭代器) - 调用该方法,得到一个迭代器对象(必须有
next()方法) - 循环调用
iterator.next(),每次取value属性,直到done为true - 将所有
value按顺序收集,构成新数组或作为函数参数传入
哪些对象能被扩展?关键看有没有合法迭代器
并非所有对象都支持扩展。只有实现了迭代器协议的对象才可用 ...:
- 原生可迭代对象:Array、String、Map、Set、TypedArray、arguments、NodeList 等
-
自定义对象:只要手动实现
[Symbol.iterator]()并返回符合规范的迭代器即可 -
不可迭代对象:普通 plain object(如
{a:1, b:2})、null、undefined、number、boolean —— 直接展开会报TypeError: X is not iterable
手动模拟扩展运算符的行为
下面这段代码等价于 [...iterable]:
立即学习“Java免费学习笔记(深入)”;
function toArray(iterable) {
const iterator = iterable[Symbol.iterator]();
const result = [];
let next;
while (!(next = iterator.next()).done) {
result.push(next.value);
}
return result;
}
注意:真实引擎优化了这个过程(例如对数组做内部快速路径),但语义上完全一致。你甚至可以用它来“窥探”迭代器行为 —— 比如 toArray(map.keys()) 就是 [...map.keys()] 的手动版。
常见误区:迭代器只执行一次
迭代器对象是消耗性的 —— 同一个迭代器多次展开会得到空结果:
const iter = [1,2,3][Symbol.iterator](); console.log([...iter]); // [1, 2, 3] console.log([...iter]); // [] ← 迭代器已耗尽
因此,扩展运算符每次展开都必须重新获取迭代器(即重新调用 [Symbol.iterator]()),否则无法重复使用。


















