Trong bài viết này, ta sẽ cùng tìm hiểu về Iterator và Iterable trong JavaScript cùng với sự trợ giúp của các ví dụ dẫn chứng.
Iterator và Iterable trong JavaScript
JavaScript cung cấp một giao thức để duyệt qua các cấu trúc dữ liệu. Giao thức này xác định cách các cấu trúc dữ liệu này được duyệt qua bằng cách sử dụng vòng lặp for...of.
Giao thức có thể được chia thành như sau:
- Iterator.
- Iterable.
Giao thức Iterable đề cập đến một giao thức Iterable phải có khóa Symbol.iterator.
Iterable trong JavaScript
Các cấu trúc dữ liệu có phương thức Symbol.iterator()được gọi là các Iterable. Ví dụ: Mảng, Chuỗi ký tự, Set,…
Các giao thức Iterator trong JavaScript
Một Iterator là một đối tượng được trả về bởi phương thức Symbol.iterator().
Iterator cung cấp phương thức next()để truy cập từng phần tử của cấu trúc dữ liệu có thể lặp tại một thời điểm.
Ví dụ:
1 2 3 4 5 6 |
const a = [100, 150 , 230]; const iterator = a[Symbol.iterator](); console.log(iterator); const b = 'Lập trình JavaScript'; const iterator2 = b[Symbol.iterator](); console.log(iterator2); |
Ở đây, việc gọi phương thức Symbol.iterator() cho cả mảng và chuỗi sẽ trả về các đối tượng Iterator tương ứng của chúng.
Duyệt qua các đối tượng Iterable
Ta có thể sử dụng vòng lặp for…ofđể duyệt qua các đối tượng Iterable.
Ta có thể thực hiện việc lặp thông qua phương thức Symbol.iterator()như sau.
Ví dụ:
1 2 3 4 |
const a = [100, 150, 160, 200, 250]; for (let i of a[Symbol.iterator]()) { console.log(i); } |
Kết quả:
1 2 3 4 5 |
100 150 160 200 250 |
Hoặc ta có thể chỉ cần lặp qua một mảng như sau.
Ví dụ:
1 2 3 4 |
const a = [150, 160, 170, 190, 250, 270]; for (let i of a) { console.log(i); } |
Kết quả:
1 2 3 4 5 6 |
150 160 170 190 250 270 |
Ở đây, đối tượng Iterator cho phép vòng lặp for...oflặp qua một mảng và trả về từng giá trị.
Phương thức next()
Đối tượng Iterator có một phương thức next() trả về phần tử tiếp theo trong chuỗi. Phương thức next() chứa hai thuộc tính: valuevà done.
- Thuộc tính value có thể thuộc bất kỳ kiểu dữ liệu nào và đại diện cho giá trị hiện tại trong chuỗi.
- Thuộc tính done là một giá trị kiểu dữ liệu boolean cho biết quá trình lặp có hoàn thành hay không. Nếu quá trình lặp chưa hoàn thành, thuộc tính done được đặt giá trị false, nếu không, thuộc tính được đặt thành true.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 |
const a = ['J', 'a', 'v', 'a', 's','c','r','i','p', 't']; let iterator = a[Symbol.iterator](); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); |
Kết quả:
1 2 3 4 5 6 7 8 9 10 |
{value: 'J', done: false} {value: 'a', done: false} {value: 'v', done: false} {value: 'a', done: false} {value: 's', done: false} {value: 'c', done: false} {value: 'r', done: false} {value: 'i', done: false} {value: 'p', done: false} {value: 't', done: false} |
Ta có thể gọi phương thức next() nhiều lần để lặp qua một đối tượng arrIterator.
- Phương thức next() trả về một đối tượng có hai thuộc tính: valuevà done.
- Khi phương thức next() đạt đến phần cuối của dãy, thuộc tính done được đặt thành giá trị false.
Ví dụ 2:
1 2 3 4 |
const a = ['J', 'a', 'v', 'a', 's','c','r','i','p', 't']; for (let i of a) { console.log(i); } |
Kết quả:
1 2 3 4 5 6 7 8 9 10 |
J a v a s c r i p t |
Vòng lặp for…of thực hiện hoàn toàn giống như chương trình trên. Vòng lặp for…of tiếp tục gọi phương thức next() trên đối tượng Iterator. Sau khi thuộc tính done có giá trị là true, vòng lặp for…of sẽ kết thúc.
Đối tượng Iterator do người dùng tự định nghĩa
Ta cũng có thể tạo đối tượng Iterator của riêng mình và gọi phương thức next() để truy cập các phần tử tiếp theo.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function vi_du(a) { let n = 0; return { next() { if(n < a.length) { return { value: a[n++], done: false } } return { value: undefined, done: true } } } } let a = ['J', 'a', 'v', 'a', 's','c','r','i','p', 't']; let iterator = vi_du(a); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); |
Kết quả:
1 2 3 4 |
{value: 'J', done: false} {value: 'a', done: false} {value: 'v', done: false} {value: 'a', done: false} |
Trong chương trình trên, chúng ta đã tạo đối tượng Iterator của riêng mình. Hàm vi_du() trả về thuộc tính value và thuộc tính done. Mỗi lần phương thức next() được gọi, hàm vi_du() được thực thi một lần và hiển thị giá trị của một mảng. Cuối cùng, khi tất cả các phần tử của một mảng đã hết, thuộc tính done được đặt thành true, với giá trị là undefined.
Trên đây là khái niệm và ví dụ cơ bản về Iterator và Iterable trong JavaScript. Hy vọng mọi người có thể áp dụng vào trong chương trình của mình. Mọi người hãy tiếp tục theo dõi các bài tiếp theo và cập nhật các bài tiếp theo về lập trình JavaScript trên tek4 nhé!
P/s: Cảm ơn mọi người đã tin tưởng tek4!