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

当作为 for...of 的右侧、作为函数(例如 Promise.allTypedArray.from)的参数或作为数组 解构赋值 的右侧给出的值不是 可迭代对象 时,会发生 JavaScript 异常 "不可迭代"。

¥The JavaScript exception "is not iterable" occurs when the value which is given as the right-hand side of for...of, as argument of a function such as Promise.all or TypedArray.from, or as the right-hand side of an array destructuring assignment, is not an iterable object.

信息

¥Message

TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator)) (V8-based)
TypeError: x is not iterable (Firefox)
TypeError: undefined is not a function (near '...[x]...') (Safari)

错误类型

¥Error type

TypeError

什么地方出了错?

¥What went wrong?

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

¥The value which is given as the right-hand side of for...of, or as argument of a function such as Promise.all or TypedArray.from, 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.

示例

¥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); // []

也可以看看