Iterable là gì? Iterable trong JavaScript
Iterable trong JavaScript là một khái niệm liên quan đến array. Một object gọi là iterable nếu object đó sử dụng được với vòng lặp for...of
.
Dĩ nhiên, array là iterable. Ngoài ra, JavaScript còn có nhiều kiểu object khác cũng iterable, ví dụ: Set, Map, String,...
// array là iterable
let arr = [1, 2, 3];
for (let it of arr) {
console.log(it); // Kết quả lần lượt là: 1, 2, 3
}
// string là iterable
let str = "hello";
for (let ch of str) {
console.log(ch); // Kết quả lần lượt là: h, e, l, l, o
}
Sau đây, mình hãy cùng tìm hiểu xem iterable trong JavaScript hoạt động thế nào nhé!
Symbol.iterator
Để hiểu rõ về iterable trong JavaScript, mình sẽ thử tự triển khai iterable.
Ví dụ object range
sau đây (mặc định không dùng được với for...of
):
let range = {
from: 1,
to: 5,
};
for (let num of range) {
console.log(num);
}
// Uncaught TypeError: range is not iterable
Để object range
trên trở nên iterable, mình cần triển khai một phương thức với key là Symbol.iterator
. Đây là một Symbol đặc biệt và sẵn có trong JavaScript.
Khi đó, quá trình xử lý của for...of
như sau:
- Ban đầu,
for...of
gọi phương thứcSymbol.iterator
. Nếu phương thức không tồn tại thì báo lỗi, ngược lại thì trả về một object, gọi làiterator
- object có phương thứcnext
. - Tiếp theo,
for...of
hoạt động hoàn toàn dựa trên đối tượngiterator
trên. - Khi
for...of
muốn giá trị tiếp theo, nó chỉ cần gọi phương thứcnext
của iterator. - Kết quả của
next
phải là một object có dạng{done: Boolean, value: any}
. Nếudone=true
thì quá trình xử lý kết thúc, ngược lại thìvalue
chính là giá trị tiếp theo.
Sau đây là cách triển khai phương thức Symbol.iterator
cho đối tượng range
trên:
let range = {
from: 1,
to: 5,
// phương thức `Symbol.iterator`
[Symbol.iterator]() {
// phương thức này trả về một iterator object - object có phương thức next
return {
current: this.from,
last: this.to,
// khi for...of cần giá trị tiếp theo thì nó sẽ gọi phương thức next
next() {
// phương thức next trả về object dạng: {done:..., value:...}
if (this.current <= this.last) {
// done=false là chưa kết thúc
return { done: false, value: this.current++ };
} else {
// done=true là kết thúc
return { done: true };
}
},
};
},
};
// Bây giờ thì range có thể hoạt động được với for...of
for (let num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
Đó chính là cách triển khai một object iterable trong JavaScript.
Gọi iterator trực tiếp
Để hiểu rõ hơn về iterable trong JavaScript, mình sẽ thử gọi iterator trực tiếp mà không sử dụng for...of
.
Ví dụ sau đây duyệt hết các kí tự ở string:
let str = "Hello";
// gọi phương thức [Symbol.iterator]()
// phương thức này trả về đối tượng iterator chứa phương thức next()
let iterator = str[Symbol.iterator]();
// sử dụng vòng lặp while(true) để duyệt
while (true) {
// gọi phương thức next() để lấy giá trị kế tiếp
// phương thức next() trả về đối tượng có dạng {done:..., value:...}
let result = iterator.next();
// kiểm tra nếu done=true thì break để kết thúc
if (result.done) break;
// ngược lại thì in ra giá trị value
console.log(result.value);
}
Kết quả:
H
e
l
l
o
Trên đây là cách hoạt động của iterable trong JavaScript.
Mặc dù, việc gọi trực tiếp như này hầu như không bao giờ áp dụng trong thực tế. Nhưng qua đó, bạn hiểu được cách hoạt động của iterable object khi duyệt với for...of
.
So sánh iterable trong JavaScript và array-like
Đây là hai khái niệm khá giống nhau nhưng thật sự rất khác biệt.
- Iterable object là object có phương thức
Symbol.iterator
(như miêu tả bên trên). - Array-like là object có chứa chỉ số và thuộc tính
length
(giống mảng).
Trong JavaScript có nhiều object - có thể là iterable hoặc array-like hoặc cả hai.
Ví dụ, string vừa là iterable (hoạt động được với for...of
) và vừa là array-like (có chỉ số và thuộc tính length
).
Nhìn chung, iterable và array-like không phải array nên chúng không có các phương thức của mảng như push
, pop
, forEach
,...
Để giải quyết vấn đề này, bạn cần phải chuyển đổi kiểu dữ liệu từ iterable hoặc array-like sang array.
Phương thức Array.from
Phương thức Array.from
nhận đầu vào là iterable object hoặc array-like và trả về một array.
Ví dụ tạo array từ array-like:
let arrayLike = {
0: "a",
1: "b",
length: 2,
};
let arr = Array.from(arrayLike);console.log(arr.pop()); // b
Ví dụ tạo array từ iterable range
bên trên:
let range = {
from: 1,
to: 5,
// phương thức `Symbol.iterator`
[Symbol.iterator]() {
// phương thức này trả về một iterator object - object có phương thức next
return {
current: this.from,
last: this.to,
// khi for...of cần giá trị tiếp theo thì nó sẽ gọi phương thức next
next() {
// phương thức next trả về object dạng: {done:..., value :...}
if (this.current <= this.last) {
// done=false là chưa kết thúc
return { done: false, value: this.current++ };
} else {
// done=true là kết thúc
return { done: true };
}
},
};
},
};
let arr = Array.from(range);console.log(arr); // (5) [1, 2, 3, 4, 5]
Cú pháp đầy đủ của Array.from
cho phép bạn truyền vào một hàm "mapping":
Array.from(obj[, mapFn, thisArg]);
Tham số thứ hai mapFn
là một hàm được sử dụng để gọi với mỗi phần tử trước khi đưa vào mảng. Và thisArg
tương ứng với this
trong hàm mapFn
. ví dụ:
// đối tượng range được định nghĩa như ví dụ trên
// hàm mapping trả về bình phương của số num
let arr = Array.from(range, (num) => num * num);
// kết quả
console.log(arr); // (5) [1, 4, 9, 16, 25]
Tổng kết
Iterable trong JavaScript là object có thể sử dụng được với vòng lặp for...of
.
- Về cơ bản, iterable object phải có phương thức
Symbol.iterator
.- Kết quả của việc gọi phương thức
obj[Symbol.iterator]()
là một object iterator. Đây là object chịu tránh nhiệm trong việc duyệt iterable object. - Iterator object phải có phương thức
next
. Và phương thứcnext()
trả về đối tượng có dạng{done: Boolean, value: Any}
. Vớidone=true
khi kết thúc quá trình duyệt, ngược lại thìvalue
là giá trị kế tiếp.
- Kết quả của việc gọi phương thức
- Phương thức
Symbol.iterator
được gọi từfor...of
, nhưng cũng có thể gọi trực tiếp không quafor...of
. - Iterable và array-like khá giống nhau, nhưng đều không phải là
array
. - Có thể dùng phương thức
Array.from
để tạo array mới từ iterable object hoặc array-like.
Tham khảo:
★ Nếu bạn thấy bài viết này hay thì hãy theo dõi mình trên Facebook để nhận được thông báo khi có bài viết mới nhất nhé:
- Facebook Fanpage: Complete JavaScript
- Facebook Group: Hỏi đáp JavaScript VN
Bình luận