/ / Cách sử dụng Trình tạo và Trình lặp trong JavaScript

Cách sử dụng Trình tạo và Trình lặp trong JavaScript

javascript featured

Việc lặp lại các bộ sưu tập dữ liệu bằng cách sử dụng các vòng lặp truyền thống có thể nhanh chóng trở nên cồng kềnh và chậm chạp, đặc biệt là khi xử lý lượng dữ liệu khổng lồ.


Trình tạo và Trình lặp JavaScript cung cấp giải pháp để lặp lại hiệu quả các bộ sưu tập dữ liệu lớn. Sử dụng chúng, bạn có thể kiểm soát luồng lặp, tạo ra từng giá trị một, đồng thời tạm dừng và tiếp tục quá trình lặp.

Tại đây, bạn sẽ trình bày những kiến ​​thức cơ bản và nội dung bên trong của một trình lặp JavaScript và cách bạn có thể tạo một trình lặp theo cách thủ công và sử dụng một trình tạo.


Trình lặp JavaScript

Trình lặp là một đối tượng JavaScript thực hiện giao thức trình lặp. Những đối tượng này làm như vậy bằng cách có một Kế tiếp phương pháp. Phương thức này trả về một đối tượng thực hiện IteratorResult giao diện.

Các IteratorResult giao diện bao gồm hai thuộc tính: xonggiá trị. Các xong thuộc tính là một boolean trả về SAI nếu iterator có thể tạo ra giá trị tiếp theo trong chuỗi của nó hoặc ĐÚNG VẬY nếu iterator đã hoàn thành trình tự của nó.

Các giá trị thuộc tính là một giá trị JavaScript được trình vòng lặp trả về trong trình tự của nó. Khi một iterator hoàn thành trình tự của nó (khi xong === ĐÚNG VẬY), thuộc tính này trả về không xác định.

Như tên ngụ ý, trình vòng lặp cho phép bạn “lặp” qua các đối tượng JavaScript chẳng hạn như mảng hoặc bản đồ. Hành vi này có thể xảy ra do giao thức có thể lặp lại.

Trong JavaScript, giao thức có thể lặp lại là một cách tiêu chuẩn để xác định các đối tượng mà bạn có thể lặp lại, chẳng hạn như trong một cho…của vòng.

Ví dụ:

 const fruits = ["Banana", "Mango", "Apple", "Grapes"];

for (const iterator of fruits) {
  console.log(iterator);
}

/*
Banana
Mango
Apple
Grapes
*/

Ví dụ này lặp đi lặp lại trên hoa quả mảng sử dụng một cho…của vòng. Trong mỗi lần lặp, nó ghi giá trị hiện tại vào bàn điều khiển. Điều này là có thể bởi vì các mảng có thể lặp lại.

Một số loại JavaScript, chẳng hạn như Mảng, Chuỗi, Tập hợp và Bản đồ, là các lần lặp tích hợp sẵn vì chúng (hoặc một trong các đối tượng trong chuỗi nguyên mẫu của chúng) triển khai một @@ iterator phương pháp.

Các loại khác, chẳng hạn như Đối tượng, không thể lặp lại theo mặc định.

Ví dụ:

 const iterObject = {
  cars: ["Tesla", "BMW", "Toyota"],
  animals: ["Cat", "Dog", "Hamster"],
  food: ["Burgers", "Pizza", "Pasta"],
};

for (const iterator of iterObject) {
  console.log(iterator);
}

Ví dụ này minh họa điều gì sẽ xảy ra khi bạn cố gắng lặp lại một đối tượng không thể lặp lại.

Làm cho một đối tượng có thể lặp lại

Để làm cho một đối tượng có thể lặp lại, bạn phải triển khai một Biểu tượng.iterator phương thức trên đối tượng. Để có thể lặp lại, phương thức này phải trả về một đối tượng thực hiện IteratorResult giao diện.

Các Biểu tượng.iterator biểu tượng phục vụ cùng một mục đích như @@ iterator và có thể được sử dụng thay thế cho nhau trong “đặc điểm kỹ thuật” nhưng không phải trong mã như @@ iterator không phải là cú pháp JavaScript hợp lệ.

Các khối mã bên dưới cung cấp một ví dụ về cách làm cho một đối tượng có thể lặp lại bằng cách sử dụng iterObject.

Đầu tiên, thêm Biểu tượng.iterator phương pháp để iterObject sử dụng khai báo hàm.

Như vậy:

 iterObject[Symbol.iterator] = function () {
  
}

Tiếp theo, bạn sẽ cần truy cập tất cả các khóa trong đối tượng mà bạn muốn có thể lặp lại. Bạn có thể truy cập các phím bằng cách sử dụng Object.keys phương thức, trả về một mảng các thuộc tính có thể đếm được của một đối tượng. Để trả về một mảng iterObjectchìa khóa của, vượt qua cái này từ khóa làm đối số cho Object.keys.

Ví dụ:

 let objProperties = Object.keys(this)

Truy cập vào mảng này sẽ cho phép bạn xác định hành vi lặp lại của đối tượng.

Tiếp theo, bạn cần theo dõi các lần lặp lại của đối tượng. Bạn có thể đạt được điều này bằng cách sử dụng các biến đếm.

Ví dụ:

 let propertyIndex = 0;
let childIndex = 0;

Bạn sẽ sử dụng biến đếm đầu tiên để theo dõi các thuộc tính của đối tượng và biến thứ hai để theo dõi các thuộc tính con của thuộc tính.

Tiếp theo, bạn sẽ cần triển khai và trả lại Kế tiếp phương pháp.

Như vậy:

 return {
  next() {
    
  }
}

Bên trong Kế tiếp phương thức, bạn sẽ cần xử lý trường hợp cạnh xảy ra khi toàn bộ đối tượng đã được lặp lại. Để xử lý trường hợp cạnh, bạn phải trả lại một đối tượng với giá trị đặt thành không xác địnhxong đặt thành ĐÚNG VẬY.

Nếu trường hợp này không được xử lý, việc cố gắng lặp lại đối tượng sẽ dẫn đến một vòng lặp vô hạn.

Đây là cách xử lý trường hợp cạnh:

 if (propertyIndex > objProperties.length - 1) {
  return {
    value: undefined,
    done: true,
  };
}

Tiếp theo, bạn sẽ cần truy cập các thuộc tính đối tượng và các phần tử con của chúng bằng cách sử dụng các biến bộ đếm mà bạn đã khai báo trước đó.

Như vậy:

 
const properties = this[objProperties[propertyIndex]];
    
const property = properties[childIndex];

Tiếp theo, bạn cần triển khai một số logic để tăng các biến bộ đếm. Logic sẽ thiết lập lại trẻ em Index khi không còn phần tử nào tồn tại trong mảng của thuộc tính và chuyển sang thuộc tính tiếp theo trong đối tượng. Ngoài ra, nó sẽ tăng trẻ em Indexnếu vẫn còn các phần tử trong mảng của thuộc tính hiện tại.

Ví dụ:

 
if (childIndex >= properties.length - 1) {
  
  // reset child index
  childIndex = 0;
        
  
  propertyIndex++;
} else {
  
  childIndex++
}

Cuối cùng, trả lại một đối tượng với xong thuộc tính được đặt thành SAIgiá trị thuộc tính được đặt thành phần tử con hiện tại trong lần lặp.

Ví dụ:

 return {
  done: false,
  value: property,
};

bạn đã hoàn thành Biểu tượng.iterator chức năng phải tương tự như khối mã bên dưới:

 iterObject[Symbol.iterator] = function () {
  const objProperties = Object.keys(this);
  let propertyIndex = 0;
  let childIndex = 0;

  return {
    next: () => {
      
      if (propertyIndex > objProperties.length - 1) {
        return {
          value: undefined,
          done: true,
        };
      }

      
      const properties = this[objProperties[propertyIndex]];
    
      const property = properties[childIndex];

      
      if (childIndex >= properties.length - 1) {
        
        // reset child index
        childIndex = 0;
        
        
        propertyIndex++;
      } else {
        
        childIndex++
      }

      return {
        done: false,
        value: property,
      };
    },
  };
};

Chạy một cho…của vòng lặp trên iterObject sau khi triển khai này sẽ không gây ra lỗi vì nó thực hiện một Biểu tượng.iterator phương pháp.

Việc triển khai các trình vòng lặp theo cách thủ công, như chúng tôi đã làm ở trên, không được khuyến khích vì nó rất dễ xảy ra lỗi và logic có thể khó quản lý.

Trình tạo JavaScript

Trình tạo JavaScript là một chức năng mà bạn có thể tạm dừng và tiếp tục thực thi nó bất cứ lúc nào. Hành vi này cho phép nó tạo ra một chuỗi các giá trị theo thời gian.

Một hàm tạo, là một hàm trả về một Trình tạo, cung cấp một giải pháp thay thế cho việc tạo các trình vòng lặp.

Bạn có thể tạo một hàm tạo giống như cách bạn tạo một khai báo hàm trong JavaScript. Sự khác biệt duy nhất là bạn phải thêm dấu hoa thị (*) vào từ khóa hàm.

Ví dụ:

 function* example () {
  return "Generator"
}

Khi bạn gọi một hàm bình thường trong JavaScript, nó sẽ trả về giá trị được chỉ định bởi trở lại từ khóa hoặc không xác định nếu không thì. Nhưng một hàm tạo không trả về bất kỳ giá trị nào ngay lập tức. Nó trả về một đối tượng Trình tạo mà bạn có thể gán cho một biến.

Để truy cập giá trị hiện tại của iterator, hãy gọi Kế tiếp phương thức trên đối tượng Generator.

Ví dụ:

 const gen = example();

console.log(gen.next()); // { value: 'Generator', done: true }

Trong ví dụ trên, các giá trị tài sản đến từ một trở lại từ khóa, chấm dứt hiệu quả trình tạo. Hành vi này nói chung là không mong muốn với các hàm tạo, vì điểm khác biệt của chúng với các hàm thông thường là khả năng tạm dừng và khởi động lại quá trình thực thi.

từ khóa năng suất

Các sản lượng từ khóa cung cấp một cách để lặp qua các giá trị trong trình tạo bằng cách tạm dừng thực thi hàm trình tạo và trả về giá trị theo sau nó.

Ví dụ:

 function* example() {
  yield "Model S"
  yield "Model X"
  yield "Cyber Truck"

  return "Tesla"
}

const gen = example();

console.log(gen.next()); // { value: 'Model S', done: false }

Trong ví dụ trên, khi Kế tiếp phương thức được gọi trên ví dụ trình tạo, nó sẽ tạm dừng mỗi khi gặp sản lượng từ khóa. Các xong tài sản cũng sẽ được đặt thành SAI cho đến khi nó gặp một trở lại từ khóa.

gọi các Kế tiếp phương pháp nhiều lần trên ví dụ trình tạo để chứng minh điều này, bạn sẽ có kết quả sau đây làm đầu ra.

 console.log(gen.next()); // { value: 'Model X', done: false }
console.log(gen.next()); // { value: 'Cyber Truck', done: false }
console.log(gen.next()); // { value: 'Tesla', done: true }

console.log(gen.next());

Bạn cũng có thể lặp qua một đối tượng Trình tạo bằng cách sử dụng cho…của vòng.

Ví dụ:

 for (const iterator of gen) {
  console.log(iterator);
}

/*
Model S
Model X
Cyber Truck
*/

Sử dụng Iterator và Generator

Mặc dù trình vòng lặp và trình tạo có vẻ giống như các khái niệm trừu tượng, nhưng thực tế không phải vậy. Chúng có thể hữu ích khi làm việc với các luồng dữ liệu và bộ sưu tập dữ liệu vô hạn. Bạn cũng có thể sử dụng chúng để tạo số nhận dạng duy nhất. Các thư viện quản lý trạng thái như MobX-State-Tree (MST) cũng sử dụng chúng dưới vỏ bọc.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *