类型错误:'x' 不可迭代

spread 的值进入数组或函数调用时,作为 for...of 的右侧给出,作为函数的参数(例如 Promise.allSet()),或作为数组 解构赋值 的右侧给出,不是 可迭代对象 时,会发生 JavaScript 异常 "不可迭代"。当 Array.fromAsync()for await...of非异步可迭代 一起使用时也会遇到此错误。

¥The JavaScript exception "is not iterable" occurs when the value which is spread into an array or function call, given as the right-hand side of for...of, as argument of a function such as Promise.all or Set(), or as the right-hand side of an array destructuring assignment, is not an iterable object. This error is also encountered when Array.fromAsync() or for await...of is used with a non-async iterable.

信息

¥Message

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)

错误类型

¥Error type

TypeError

什么地方出了错?

¥What went wrong?

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

¥The value which is spread into an array or function call, given as the right-hand side of for...of, or as argument of a function such as Promise.all or Set(), or as the right-hand side of an array destructuring assignment, is not an iterable object. An iterable can be a built-in iterable type such as Array, String or Map, a generator result, or an object implementing the iterable protocol.

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;

示例

¥Examples

数组解构不可迭代的数组

¥Array destructuring a non-iterable

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

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

console.log(value1, value2);

在某些运行时环境中,不可迭代可能会变成 undefined

¥The non-iterable might turn to be undefined in some runtime environments.

迭代对象属性

¥Iterating over Object properties

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

¥In JavaScript, Objects are not iterable unless they implement the iterable protocol. Therefore, you cannot use for...of to iterate over the properties of an object.

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

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

¥Instead you have to use Object.keys or Object.entries, to iterate over the properties or entries of an object.

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

¥Another option for this use case might be to use a 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);
}

迭代生成器

¥Iterating over a generator

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

¥Generator functions are functions you call to produce an iterable object.

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

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

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

¥When they are not called, the Function object corresponding to the generator is callable, but not iterable. Calling a generator produces an iterable object which will iterate over the values yielded during the execution of the generator.

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

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

迭代自定义可迭代对象

¥Iterating over a custom iterable

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

¥Custom iterables can be created by implementing the Symbol.iterator method. You must be certain that your iterator method returns an object which is an iterator, which is to say it must have a next method.

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

这是一个正确的实现:

¥Here is a correct implementation:

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

Array.from(myEmptyIterable); // []

也可以看看