类型错误:'x' 不可迭代
当 spread 的值进入数组或函数调用时,作为 for...of
的右侧给出,作为函数的参数(例如 Promise.all
或 Set()
),或作为数组 解构赋值 的右侧给出,不是 可迭代对象 时,会发生 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)
错误类型
什么地方出了错?
¥What went wrong?
作为数组或函数调用中的 spread 的值,作为 for...of
的右侧,或作为函数(例如 Promise.all
或 Set()
)的参数,或作为数组 解构赋值 的右侧给出,不是 可迭代对象。可迭代可以是内置可迭代类型(例如 Array
、String
或 Map
)、生成器结果或实现 可迭代协议 的对象。
¥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.
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;
示例
数组解构不可迭代的数组
¥Array destructuring a non-iterable
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, Object
s are not iterable unless they implement
the iterable protocol.
Therefore, you cannot use for...of
to iterate over the properties of an object.
const obj = { France: "Paris", England: "London" };
for (const p of obj) {
// …
} // TypeError: obj is not iterable
相反,你必须使用 Object.keys
或 Object.entries
来迭代对象的属性或条目。
¥Instead you have to use Object.keys
or Object.entries
, to
iterate over the properties or entries of an object.
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
:
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.
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.
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.
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:
const myEmptyIterable = {
[Symbol.iterator]() {
return [][Symbol.iterator]();
},
};
Array.from(myEmptyIterable); // []
也可以看看
¥See also