ES6 - Trình lặp lại

Giới thiệu về Iterator

Iterator là một đối tượng cho phép chúng ta truy cập một tập hợp các đối tượng tại một thời điểm.

Theo mặc định, các kiểu tích hợp sau có thể lặp lại:

  • String
  • Array
  • Map
  • Set

Một đối tượng được coi là iterable, nếu đối tượng triển khai một hàm có khóa là [Symbol.iterator]và trả về một trình lặp. Vòng lặp for ... of có thể được sử dụng để lặp lại một tập hợp.

Thí dụ

Ví dụ sau khai báo một mảng, đánh dấu và lặp qua nó bằng cách sử dụng for..of vòng.

<script>
   let marks = [10,20,30]
   //check iterable using for..of
   for(let m of marks){
      console.log(m);
   }
</script>

Đầu ra của đoạn mã trên sẽ như dưới đây:

10
20
30

Thí dụ

Ví dụ sau khai báo một mảng, đánh dấu và truy xuất một đối tượng vòng lặp. Các[Symbol.iterator]()có thể được sử dụng để truy xuất một đối tượng trình lặp. Phương thức next () của trình vòng lặp trả về một đối tượng với'value''done'tính chất . 'done' là Boolean và trả về true sau khi đọc tất cả các mục trong bộ sưu tập.

<script>
   let marks = [10,20,30]
   let iter = marks[Symbol.iterator]();
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
</script>

Đầu ra của đoạn mã trên sẽ như hình dưới đây:

{value: 10, done: false}
{value: 20, done: false}
{value: 30, done: false}
{value: undefined, done: true}

Có thể lặp lại tùy chỉnh

Một số kiểu nhất định trong JavaScript có thể lặp lại được (Ví dụ: Mảng, Bản đồ, v.v.) trong khi những kiểu khác thì không (Ví dụ: Lớp). Các loại JavaScript không thể lặp lại theo mặc định có thể được lặp lại bằng cách sử dụng giao thức có thể lặp lại.

Ví dụ sau định nghĩa một lớp có tên CustomerListlưu trữ nhiều đối tượng khách hàng dưới dạng một mảng. Mỗi đối tượng khách hàng có thuộc tính firstName và lastName.

Để làm cho lớp này có thể lặp lại, lớp phải triển khai [Symbol.iterator]()chức năng. Hàm này trả về một đối tượng trình lặp. Đối tượng vòng lặp có một chức năngnext trả về một đối tượng {value:'customer',done:true/false}.

<script>
   //user defined iterable
   class CustomerList {
      constructor(customers){
         //adding customer objects to an array
         this.customers = [].concat(customers)
      }
      //implement iterator function
      [Symbol.iterator](){
         let count=0;
         let customers = this.customers
         return {
            next:function(){
            //retrieving a customer object from the array
               let customerVal = customers[count];
               count+=1;
               if(count<=customers.length){
                  return {
                     value:customerVal,
                     done:false
                  }
               }
               //return true if all customer objects are iterated
               return {done:true}
            }
         }
      }
   }
   //create customer objects
   let c1={
      firstName:'Sachin',
      lastName:'Tendulkar'
   }
   let c2={
      firstName:'Rahul',
      lastName:'Dravid'
   }
   //define a customer array and initialize it let customers=[c1,c2]
   //pass customers to the class' constructor
   let customersObj = new CustomerList(customers);
   //iterating using for..of
   for(let c of customersObj){
      console.log(c)
   }
   //iterating using the next() method
   let iter = customersObj[Symbol.iterator]();
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
</script>

Đầu ra của đoạn mã trên sẽ như sau:

{firstName: "Sachin", lastName: "Tendulkar"}
{firstName: "Rahul", lastName: "Dravid"}
{
   done: false
   value: {
      firstName: "Sachin",
      lastName: "Tendulkar"
   }
}
{
   done: false
   value: {
      firstName: "Rahul",
      lastName: "Dravid"
   }
}
{done: true}

Máy phát điện

Trước ES6, các hàm trong JavaScript tuân theo mô hình chạy để hoàn thành. ES6 giới thiệu các chức năng được gọi là Máy phát điện có thể dừng giữa chừng và sau đó tiếp tục từ nơi nó đã dừng.

Trình tạo tiền tố tên hàm bằng ký tự dấu hoa thị * và chứa một hoặc nhiều yieldcác câu lệnh. Cácyield từ khóa trả về một đối tượng trình lặp.

Cú pháp

function * generator_name() {
   yield value1
   ...
   yield valueN
}

Thí dụ

Ví dụ xác định một hàm máy phát điện getMarksvới ba câu lệnh lợi nhuận. Không giống như các chức năng bình thường,generator function getMarks(), khi được gọi, không thực thi hàm nhưng trả về một đối tượng trình vòng lặp giúp bạn thực thi mã bên trong hàm trình tạo.

Trong cuộc gọi đầu tiên tới markIter.next()các hoạt động lúc đầu sẽ chạy và câu lệnh lợi nhuận tạm dừng việc thực thi trình tạo. Các cuộc gọi tiếp theo đếnmarkIter.next() sẽ tiếp tục chức năng trình tạo cho đến lần tiếp theo yield biểu hiện.

<script>
   //define generator function
   function * getMarks(){
      console.log("Step 1")
      yield 10
      console.log("Step 2")
      yield 20
      console.log("Step 3")
      yield 30
      console.log("End of function")
   }
   //return an iterator object
      let markIter = getMarks()
   //invoke statements until first yield
      console.log(markIter.next())
   //resume execution after the last yield until second yield expression
      console.log(markIter.next())
   //resume execution after last yield until third yield expression
      console.log(markIter.next())
      console.log(markIter.next()) // iteration is completed;no value is returned
</script>

Đầu ra của đoạn mã trên sẽ như được đề cập bên dưới:

Step 1
{value: 10, done: false}
Step 2
{value: 20, done: false}
Step 3
{value: 30, done: false}
End of function
{value: undefined, done: true}

Thí dụ

Ví dụ sau tạo một dãy số chẵn vô hạn thông qua

* Chức năng tạo EvenNumberGenerator.

Chúng ta có thể lặp lại tất cả các số chẵn bằng cách sử dụng next() hoặc sử dụng for of vòng lặp như hình dưới đây

<script>
   function * evenNumberGenerator(){
      let num = 0;
      while(true){
         num+=2
         yield num
      }
   }
   // display first two elements
   let iter = evenNumberGenerator();
   console.log(iter.next())
   console.log(iter.next())
   //using for of to iterate till 12
   for(let n of evenNumberGenerator()){
      if(n==12)break;
      console.log(n);
   }
</script>

Đầu ra của đoạn mã trên sẽ như sau:

{value: 2, done: false}
{value: 4, done: false}
2
4
6
8
10