TypeError: 'x' 不可迭代

当扩展到数组或函数调用中的值,作为 for...of 的右侧,作为函数(如 Promise.allSet())的参数,或作为数组 解构赋值 的右侧时,该值不是 可迭代对象,则会发生 JavaScript 异常 "is not iterable"。当使用 Array.fromAsync()for await...of 以及 非异步可迭代对象 时,也会遇到此错误。

消息

TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function (V8-based & Safari)
TypeError: %Array%.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function (V8-based & Safari)
TypeError: Array.fromAsync requires that the property of the first argument, items[Symbol.asyncIterator], when exists, be a function (V8-based & Safari)
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator)) (V8-based)
TypeError: x is not async iterable (V8-based)
TypeError: x is not iterable (V8-based & Firefox)
TypeError: undefined is not a function (near '...y of x...') (Safari)
TypeError: Array.from: no function (Safari)
TypeError: Type error (Safari)

错误类型

哪里出错了?

扩展到数组或函数调用中的值,作为 for...of 的右侧,作为函数(如 Promise.allSet())的参数,或作为数组 解构赋值 的右侧时,该值不是 可迭代对象。可迭代对象可以是内置的可迭代类型,如 ArrayStringMap,生成器结果,或实现 可迭代协议 的对象。

js
const nonIterable1 = {};
const nonIterable2 = { [Symbol.iterator]: 1 };

[...nonIterable1];
Math.max(...nonIterable1);
for (const x of nonIterable1);
new Set(nonIterable1);
Array.from(nonIterable2);
new Int8Array(nonIterable2);
const [] = nonIterable1;

示例

数组解构非可迭代对象

js
const myobj = { arrayOrObjProp1: {}, arrayOrObjProp2: [42] };

const {
  arrayOrObjProp1: [value1],
  arrayOrObjProp2: [value2],
} = myobj; // TypeError: object is not iterable

console.log(value1, value2);

非可迭代对象在某些运行时环境中可能会变成 undefined

迭代对象属性

在 JavaScript 中,Object 不是可迭代的,除非它们实现了 可迭代协议。因此,您不能使用 for...of 来迭代对象的属性。

js
const obj = { France: "Paris", England: "London" };
for (const p of obj) {
  // …
} // TypeError: obj is not iterable

相反,您必须使用 Object.keysObject.entries 来迭代对象的属性或条目。

js
const obj = { France: "Paris", England: "London" };
// Iterate over the property names:
for (const country of Object.keys(obj)) {
  const capital = obj[country];
  console.log(country, capital);
}

for (const [country, capital] of Object.entries(obj)) {
  console.log(country, capital);
}

此用例的另一种选择可能是使用 Map

js
const map = new Map();
map.set("France", "Paris");
map.set("England", "London");
// Iterate over the property names:
for (const country of map.keys()) {
  const capital = map.get(country);
  console.log(country, capital);
}

for (const capital of map.values()) {
  console.log(capital);
}

for (const [country, capital] of map.entries()) {
  console.log(country, capital);
}

迭代生成器

生成器函数 是您调用以生成可迭代对象的函数。

js
function* generate(a, b) {
  yield a;
  yield b;
}

for (const x of generate) {
  console.log(x);
} // TypeError: generate is not iterable

当未调用它们时,与生成器相对应的 Function 对象是可调用的,但不可迭代的。调用生成器会生成一个可迭代对象,该对象将迭代在生成器执行期间产生的值。

js
function* generate(a, b) {
  yield a;
  yield b;
}

for (const x of generate(1, 2)) {
  console.log(x);
}

迭代自定义可迭代对象

通过实现 Symbol.iterator 方法可以创建自定义可迭代对象。您必须确保您的迭代器方法返回一个迭代器对象,也就是说它必须有一个 next 方法。

js
const myEmptyIterable = {
  [Symbol.iterator]() {
    return []; // [] is iterable, but it is not an iterator — it has no next method.
  },
};

Array.from(myEmptyIterable); // TypeError: myEmptyIterable is not iterable

这是一个正确的实现

js
const myEmptyIterable = {
  [Symbol.iterator]() {
    return [][Symbol.iterator]();
  },
};

Array.from(myEmptyIterable); // []

另请参见