TypeError: 'x' is not iterable
Ngoại lệ JavaScript "is not iterable" xảy ra khi giá trị được spread vào một mảng hoặc lời gọi hàm, được dùng làm toán hạng bên phải của for...of, làm đối số của hàm như Promise.all hoặc Set(), hoặc làm toán hạng bên phải của destructuring mảng, không phải là một đối tượng iterable. Lỗi này cũng xảy ra khi Array.fromAsync() hoặc for await...of được sử dụng với non-async iterable.
Thông báo
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)
Loại lỗi
TypeError
Nguyên nhân?
Giá trị được spread vào một mảng hoặc lời gọi hàm, được dùng làm toán hạng bên phải của for...of, hoặc làm đối số của hàm như Promise.all hoặc Set(), hoặc làm nguồn của mẫu destructuring mảng, không phải là một đối tượng iterable. Một iterable có thể là kiểu iterable tích hợp sẵn như Array, String hoặc Map, kết quả của generator, hoặc một đối tượng triển khai giao thức iterable.
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;
Ví dụ
>Destructuring mảng từ một non-iterable
const myObj = { arrayOrObjProp1: {}, arrayOrObjProp2: [42] };
const {
arrayOrObjProp1: [value1],
arrayOrObjProp2: [value2],
} = myObj; // TypeError: object is not iterable
console.log(value1, value2);
Non-iterable có thể trở thành undefined trong một số môi trường chạy.
Duyệt qua các thuộc tính của Object
Trong JavaScript, Object không thể duyệt lặp trừ khi chúng triển khai giao thức iterable. Do đó, bạn không thể sử dụng for...of để duyệt qua các thuộc tính của một đối tượng.
const obj = { France: "Paris", England: "London" };
for (const p of obj) {
// …
} // TypeError: obj is not iterable
Thay vào đó, bạn phải sử dụng Object.keys hoặc Object.entries để duyệt qua các thuộc tính hoặc các mục của đối tượng.
const obj = { France: "Paris", England: "London" };
// Duyệt qua tên thuộc tính:
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);
}
Một lựa chọn khác cho trường hợp này là sử dụng Map:
const map = new Map();
map.set("France", "Paris");
map.set("England", "London");
// Duyệt qua tên thuộc tính:
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);
}
Duyệt qua một generator
Hàm generator là các hàm bạn gọi để tạo ra một đối tượng iterable.
function* generate(a, b) {
yield a;
yield b;
}
for (const x of generate) {
console.log(x);
} // TypeError: generate is not iterable
Khi chúng không được gọi, đối tượng Function tương ứng với generator có thể gọi được, nhưng không thể duyệt lặp. Gọi một generator sẽ tạo ra một đối tượng iterable có thể duyệt qua các giá trị được yield trong quá trình thực thi generator.
function* generate(a, b) {
yield a;
yield b;
}
for (const x of generate(1, 2)) {
console.log(x);
}
Duyệt qua một custom iterable
Custom iterable có thể được tạo ra bằng cách triển khai phương thức Symbol.iterator. Bạn phải đảm bảo rằng phương thức iterator của bạn trả về một đối tượng là iterator, tức là nó phải có phương thức next.
const myEmptyIterable = {
[Symbol.iterator]() {
return []; // [] là iterable, nhưng không phải là iterator — nó không có phương thức next.
},
};
Array.from(myEmptyIterable); // TypeError: myEmptyIterable is not iterable
Đây là cách triển khai đúng:
const myEmptyIterable = {
[Symbol.iterator]() {
return [][Symbol.iterator]();
},
};
Array.from(myEmptyIterable); // []