Thứ tư, 13/03/2019 | 00:00 GMT+7

Giới thiệu về Lặp lại và Trình lặp trong JavaScript


JavaScript hỗ trợ một giao thức mà các đối tượng như mảng được dùng bởi các cấu trúc điều khiển như for… of và toán tử spread ... để lặp qua dữ liệu một cách tuần tự. Điều này được gọi là có thể lặp lại và cấu trúc dữ liệu hỗ trợ chức năng này được gọi là lặp lại. Mặc dù JavaScript cung cấp các bản đồ, mảng và tập hợp với thuộc tính có thể lặp lại từ đầu, các đối tượng thuần túy không có điều này theo mặc định.

Lặp lại là cấu trúc dữ liệu cung cấp cơ chế cho phép người tiêu dùng dữ liệu khác truy cập các phần tử của nó theo cách tuần tự. Hãy tưởng tượng một cấu trúc dữ liệu tự đóng gói sẽ tải dữ liệu từng cái một theo thứ tự khi được đưa vào bên trong vòng lặp for...of .

Khái niệm về giao thức có thể lặp lại có thể được chia thành có thể lặp lại (chính cấu trúc dữ liệu) và trình lặp (loại con trỏ di chuyển qua có thể lặp). Hãy xem xét một mảng chẳng hạn, khi mảng được sử dụng trong vòng lặp for...of , thuộc tính có thể lặp được gọi là thuộc tính trả về một iterator . Thuộc tính có thể lặp lại này được đặt tên là Symbol.iterator và đối tượng mà nó trả về được dùng trên một giao diện chung được chia sẻ bởi tất cả các cấu trúc điều khiển lặp.

Theo một cách nào đó, Symbol.iterator có thể được so sánh với một nhà máy production trình vòng lặp tạo ra trình vòng lặp khi nào cấu trúc dữ liệu được đặt trong một vòng lặp.

JavaScript có thể lặp lại

Khi một trình lặp di chuyển qua cấu trúc dữ liệu và cung cấp các phần tử một cách tuần tự, đối tượng được trả về bởi có thể lặp chứa một value và một thuộc tính đã done .

Trình lặp JavaScript

Giá trị cho biết giá trị dữ liệu hiện tại được trỏ bởi trình vòng lặp và done là một boolean cho ta biết nếu trình vòng lặp đã đến phần tử cuối cùng trong cấu trúc dữ liệu.

{value, done} này được sử dụng bởi các cấu trúc như vòng lặp. Vậy làm thế nào để phương thức vòng lặp gọi đối tượng tiếp theo? Sử dụng phương thức next() được định nghĩa trong phương thức Symbol.iterator ().

Một định nghĩa tốt hơn cho thuộc tính trình vòng lặp mà tôi có thể đưa ra tại thời điểm này là thuộc tính biết cách truy cập từng phần tử từ một tập hợp và cung cấp luật logic để ngừng làm như vậy (ví dụ: nếu không còn phần tử trong mảng).

Đối tượng và Lặp lại

Các đối tượng JavaScript rất tuyệt và tất cả, nhưng tại sao chúng không có các mục lặp? Chà, một số lý do có thể là:

  • Một trong những tính năng chính của đối tượng là nó do user định nghĩa. Vì vậy, việc trượt [Symbol.iterator]() im lặng vào đối tượng sẽ tạo ra một bất ngờ khó chịu.
  • Điểm trên cũng nghĩa là user có thể thêm nó theo cách thủ công, vì tất cả các thành phần đối tượng có thể không giống nhau. Vì vậy, có một thuộc tính có thể lặp lại chung là khá vô nghĩa.
  • Nếu bạn muốn lặp qua các phần tử cấp cao nhất trong đối tượng, hãy sử dụng vòng lặp khác: a for...in vòng lặp.
  • Việc sử dụng loại đối tượng Bản đồ có thể thích hợp hơn.

Tất cả những điểm ở trên ngoại trừ điểm cuối cùng (tôi ghét phải thừa nhận rằng tôi quá hài lòng với các đối tượng thông thường để di chuyển lên bản đồ) là những lý do chính đáng để không có các mục lặp trong đối tượng, nhưng nếu sếp của bạn muốn các đối tượng JavaScript của bạn có một cái?

Một triển khai có thể lặp lại đơn giản trên các đối tượng sẽ giống như sau:

let Reptiles = {   biomes: {     water: ["Alligators", "Crocs"],     land: ["Snakes", "Turtles"]   },    [Symbol.iterator]() {     let reptilesByBiome = Object.values(this.biomes);     let reptileIndex = 0;     let biomeIndex = 0;     return {       next() {         if (reptileIndex >= reptilesByBiome[biomeIndex].length) {           biomeIndex++;           reptileIndex = 0;         }          if (biomeIndex >= reptilesByBiome.length) {           return { value: undefined, done: true };         }          return {           value: reptilesByBiome[biomeIndex][reptileIndex++],           done: false         };       }     };   } };  // let's now iterate over our new `Reptiles` iterable: for (let reptile of Reptiles) console.log(reptile); 

Đầu ra sẽ là:

Alligators Crocs Snakes Turtles 

Với ví dụ này, ta thấy các trình vòng lặp có thể được thực hiện bên trong đối tượng. Các đoạn lặp có thể là các thuộc tính mạnh mẽ cho các đối tượng giúp dễ sử dụng trong khi xử lý các tình huống nhất định và giúp ta tránh viết tên đường dẫn dài.

Bắt đầu lặp lại

Các vòng lặp như for...of có một cơ chế tích hợp để sử dụng các vòng lặp cho đến khi giá trị done đánh giá là true. Điều gì sẽ xảy ra nếu bạn muốn tự mình sử dụng có thể lặp lại mà không có vòng lặp tích hợp? Đơn giản, bạn lấy trình vòng lặp từ có thể lặp lại và sau đó gọi next () trên đó theo cách thủ công.

Với ví dụ tương tự như trên, ta có thể nhận được một iterator từ Reptiles bằng cách gọi nó Symbol.iterator như thế này:

let reptileIterator = Reptiles[Symbol.iterator](); 

Sau đó, bạn có thể sử dụng trình lặp như sau:

console.log(reptileIterator.next()); // {value: "Alligators", done: false} console.log(reptileIterator.next()); // {value: "Crocs", done: false} console.log(reptileIterator.next()); // {value: "Snakes", done: false} console.log(reptileIterator.next()); // {value: "Turtles", done: false} console.log(reptileIterator.next()); // {value: undefined, done: true}  console.log(reptileIterator.next()); // TypeError: Cannot read property 'length' of undefined 

Như bạn thấy , trình lặp có phương thức next() trả về giá trị tiếp theo trong có thể lặp. Giá trị cho done chỉ đánh giá thành true sau một next() gọi next() khác sau khi giá trị cuối cùng đã được trả về, do đó, để xem qua toàn bộ có thể lặp sẽ luôn có thêm một lệnh gọi tới next() hơn là có dữ liệu trong có thể lặp. Việc gọi lại next() sau khi một trình vòng lặp đã đi đến cuối phần có thể đọc được sẽ dẫn đến lỗi TypeError được ném ra.

Kết thúc

Tôi hy vọng rằng phần giới thiệu này sẽ giúp bạn hiểu thêm một chút về nội bộ của JavaScript cho các cấu trúc dữ liệu chẳng hạn như các đối tượng. Điều này chỉ làm trầy xước bề mặt và, nếu bạn muốn tìm hiểu thêm, tôi mời bạn đọc chương xuất sắc của Kyle Simpson trên Iterables .


Tags:

Các tin liên quan

D3.js: Hiểu các lựa chọn và so sánh với Vanilla JavaScript
2019-03-04
Xem xét Phạm vi, Ngữ cảnh, Tham chiếu Đối tượng và Thuyết minh trong JavaScript
2019-02-25
Sử dụng JavaScript Mixins
2019-02-12
Đọc mã nguồn JavaScript, sử dụng AST
2019-02-09
JavaScript Biểu thức chính quy cho Người bình thường
2019-02-07
Mẫu kế thừa nguyên mẫu JavaScript
2019-02-01
Các mẫu hướng đối tượng JavaScript: Mẫu nhà máy
2019-01-23
Đối tượng, Nguyên mẫu và Lớp trong JavaScript
2019-01-10
Thủ thuật với JavaScript Hủy cấu trúc
2018-11-26
Đừng sợ theo dõi JavaScript
2018-10-17