# TypeScript - Iterators và Generators

Xin chào bạn, ngôi sao lập trình tương lai! Chào mừng bạn đến với hành trình thú vị vào thế giới của TypeScript, nơi chúng ta sẽ khám phá vương quốc kỳ diệu của Iterators và Generators. Đừng lo lắng nếu những thuật ngữ này听起来 như công nghệ ngoài hành tinh đối với bạn lúc này - đến cuối bài hướng dẫn này, bạn sẽ sử dụng chúng như một chuyên gia! Hãy cuộn lên áo của bạn và nhảy vào!

## Iterators

Hãy tưởng tượng bạn có một hộp đồ chơi đầy những món đồ chơi khác nhau. Một iterator giống như một cây phép giúp bạn đi qua từng món đồ chơi một cách từng cái, mà không cần phải đổ toàn bộ hộp ra sàn. Đ酷, phải không? Hãy cùng xem điều này hoạt động như thế nào trong TypeScript!

### Iterators là gì?

Một iterator là một đối tượng xác định một phương thức `next()`, phương thức này trả về mục tiếp theo trong một chuỗi. Khi không còn mục nào khác, nó trả về một giá trị đặc biệt để cho biết rằng chuỗi đã kết thúc.

Hãy tạo iterator đầu tiên của chúng ta:

```typescript
function createNumberIterator() {
  let n = 0;
  return {
    next: function() {
      n += 1;
      if (n <= 5) {
        return { value: n, done: false };
      }
      return { value: undefined, done: true };
    }
  };
}

const numberIterator = createNumberIterator();
console.log(numberIterator.next()); // { value: 1, done: false }
console.log(numberIterator.next()); // { value: 2, done: false }
console.log(numberIterator.next()); // { value: 3, done: false }
console.log(numberIterator.next()); // { value: 4, done: false }
console.log(numberIterator.next()); // { value: 5, done: false }
console.log(numberIterator.next()); // { value: undefined, done: true }

Trong ví dụ này, chúng ta đã tạo một iterator đếm từ 1 đến 5. Mỗi lần chúng ta gọi next(), nó sẽ cho chúng ta biết số tiếp theo. Khi nó đạt đến 5, nó sẽ báo cho chúng ta biết rằng nó đã xong bằng cách trả về { value: undefined, done: true }.

TypeScript - Iterators and Generators

Sử dụng Iterators với vòng lặp for...of

TypeScript làm cho việc sử dụng iterators trở nên dễ dàng hơn với vòng lặp for...of. Hãy cùng xem:

function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}

for (const num of numberGenerator()) {
  console.log(num);
}
// Output:
// 1
// 2
// 3
// 4
// 5

Vòng lặp for...of này tự động sử dụng iterator để đi qua tất cả các giá trị. Nó giống như có một trợ lý robot giúp bạn picking từng món đồ chơi từ hộp cho bạn!

Generators

Bây giờ, hãy nói về generators. Nếu iterators giống như cây phép, thì generators giống như các phù thủy có thể tạo ra những cây phép này với ít công sức hơn!

Generators là gì?

Một generator là một loại hàm đặc biệt có thể dừng lại và tiếp tục, cho phép nó tạo ra một chuỗi giá trị theo từng thời điểm, thay vì tính toán chúng tất cả cùng một lúc và trả về chúng trong một mảng.

Hãy tạo generator đầu tiên của chúng ta:

function* countToFive() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}

const generator = countToFive();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3
console.log(generator.next().value); // 4
console.log(generator.next().value); // 5
console.log(generator.next().value); // undefined

Trong ví dụ này, countToFive là một hàm generator. Từ khóa yield giống như nói "Đây là giá trị tiếp theo, nhưng hãy nghỉ ngơi sau này." Mỗi lần chúng ta gọi next(), hàm chạy cho đến khi gặp yield, trả về giá trị đó, và sau đó nghỉ ngơi.

Generators với vòng lặp

Generators trở nên mạnh mẽ hơn khi kết hợp với vòng lặp. Hãy xem một ví dụ:

function* evenNumbersUnder20() {
  for (let i = 2; i < 20; i += 2) {
    yield i;
  }
}

for (const num of evenNumbersUnder20()) {
  console.log(num);
}
// Output:
// 2
// 4
// 6
// 8
// 10
// 12
// 14
// 16
// 18

Generator này yield tất cả các số chẵn dưới 20. Nó giống như một máy phát đồ chơi thông minh chỉ phân phát một số loại đồ chơi nhất định!

Sự khác biệt giữa Iterators và Generators

Bây giờ chúng ta đã thấy cả hai iterators và generators trong hành động, hãy phân tích các điểm khác biệt chính:

Tính năng Iterators Generators
Định nghĩa Một đối tượng với phương thức next() Một hàm với kí tự *
Quản lý trạng thái Thủ công Tự động
Dễ dàng tạo ra Phức tạp hơn Đơn giản hơn
Dừng lại/ Tiếp tục Không có sẵn Tự động với yield
Hiệu quả bộ nhớ Có thể hiệu quả hơn cho các bộ dữ liệu lớn Xuất sắc cho các chuỗi dài hoặc vô hạn

Iterators giống như xây dựng một robot đồ chơi từ đầu - bạn phải xác định mọi chi tiết nhỏ. Generators, mặt khác, giống như có một robot tiền제 mà bạn có thể dễ dàng tùy chỉnh. Cả hai đều có vị trí và mục đích của riêng mình!

Ví dụ thực tế

Hãy kết thúc với một ví dụ thú vị, kết hợp những gì chúng ta đã học:

function* fibonacciGenerator() {
  let a = 0, b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

const fib = fibonacciGenerator();
for (let i = 0; i < 10; i++) {
  console.log(fib.next().value);
}
// Output:
// 0
// 1
// 1
// 2
// 3
// 5
// 8
// 13
// 21
// 34

Generator này tạo ra chuỗi Fibonacci - một chuỗi toán học nổi tiếng mà trong đó mỗi số là tổng của hai số trước đó. Nó giống như một cầu thang vô tận mà mỗi bậc được xây dựng từ hai bậc trước!

Và thế là bạn đã có nó, các học trò lập trình của tôi! Chúng ta đã đi qua các vùng đất của Iterators và Generators, thấy sự tương tự và khác biệt của chúng, và thậm chí tạo ra một chút phép thuật của riêng mình. Nhớ rằng, thực hành là chìa khóa của sự hoàn hảo, vì vậy đừng ngần ngại thử nghiệm với các khái niệm này. Ai biết được những chương trình tuyệt vời nào bạn sẽ tạo ra với sức mạnh của iterator và generator? Chúc bạn lập trình vui vẻ và mã code của bạn luôn biên dịch thành công lần đầu!

Credits: Image by storyset