Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

Iterators and Iterables

บทความนี้อธิบายถึง Iterator และ Iterable protocols ใน JavaScript ซึ่งเป็นกลไกที่ทำให้ object สามารถวนซ้ำได้ โดย Iterator จะมี method `next()` ที่คืนค่า `value`...

Iterators และ Iterables ใน JavaScript

ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับ Generators ซึ่งเป็นเครื่องมือที่ช่วยให้เราสร้าง Iterators ได้อย่างง่ายดาย แต่ก่อนที่เราจะไปต่อยอด เรามาทำความเข้าใจพื้นฐานของ Iterators และ Iterables กันก่อนดีกว่าครับ ว่ามันคืออะไร ทำงานอย่างไร และมีความสำคัญอย่างไร

Iterator Protocol: กฎเกณฑ์ของ Iterator

Iterator Protocol คือข้อกำหนดที่ระบุว่า object ใดๆ ก็ตามที่ต้องการเป็น Iterator จะต้องมี method ชื่อ next() ซึ่ง method นี้จะ:

  • คืนค่า object ที่มี property สองตัว: value และ done
  • value: คือค่าถัดไปในลำดับ (sequence)
  • done: เป็น boolean ที่บอกว่า iterator ได้สิ้นสุดลงแล้วหรือไม่ (true ถ้าสิ้นสุด, false ถ้ายังมีค่าให้วนซ้ำ)

ตัวอย่าง: สร้าง Iterator แบบง่ายๆ ที่วนซ้ำเลข 1 ถึง 3

const myIterator = {
  data: [1, 2, 3],
  index: 0,
  next: function() {
    if (this.index < this.data.length) {
      return { value: this.data[this.index++], done: false };
    } else {
      return { value: undefined, done: true };
    }
  }
};

console.log(myIterator.next()); // { value: 1, done: false }
console.log(myIterator.next()); // { value: 2, done: false }
console.log(myIterator.next()); // { value: 3, done: false }
console.log(myIterator.next()); // { value: undefined, done: true }

จากตัวอย่างข้างต้น myIterator เป็น object ที่มี method next() ซึ่งปฏิบัติตาม Iterator Protocol อย่างเคร่งครัด

Iterable Protocol: ทำให้ Object ของเราวนซ้ำได้

Iterable Protocol คือข้อกำหนดที่ระบุว่า object ใดๆ ก็ตามที่ต้องการเป็น Iterable (วนซ้ำได้) จะต้องมี method ที่มี symbol ชื่อ Symbol.iterator ซึ่ง method นี้จะต้อง:

  • คืนค่า Iterator object

พูดง่ายๆ คือ Iterable เป็น object ที่สามารถ "ให้กำเนิด" Iterator ได้

ตัวอย่าง: สร้าง Iterable ที่วนซ้ำเลข 1 ถึง 3 โดยใช้ Iterator ที่เราสร้างไว้ก่อนหน้า

const myIterable = {
  data: [1, 2, 3],
  [Symbol.iterator]: function() {
    let index = 0;
    const data = this.data; // เก็บค่า data ไว้เพื่อใช้ใน iterator
    return {
      next: function() {
        if (index < data.length) {
          return { value: data[index++], done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

const iterator = myIterable[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

ในตัวอย่างนี้ myIterable มี method ที่มีชื่อ Symbol.iterator ซึ่งคืนค่า Iterator object ที่สามารถวนซ้ำข้อมูลใน data ได้

การใช้ for...of Loop กับ Iterables

สิ่งที่ทำให้ Iterables มีประโยชน์อย่างมากคือการที่มันสามารถใช้ร่วมกับ for...of loop ได้อย่างง่ายดาย for...of loop จะเรียกใช้ method Symbol.iterator ของ Iterable object โดยอัตโนมัติ และวนซ้ำค่าที่ได้จาก Iterator จนกว่า done จะเป็น true

ตัวอย่าง: ใช้ for...of loop กับ myIterable ที่เราสร้างไว้ก่อนหน้า

const myIterable = {
  data: [1, 2, 3],
  [Symbol.iterator]: function() {
    let index = 0;
    const data = this.data; // เก็บค่า data ไว้เพื่อใช้ใน iterator
    return {
      next: function() {
        if (index < data.length) {
          return { value: data[index++], done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

for (const value of myIterable) {
  console.log(value); // 1, 2, 3
}

จะเห็นได้ว่า for...of loop ช่วยให้เราวนซ้ำข้อมูลใน myIterable ได้อย่างง่ายดาย โดยไม่ต้องจัดการกับ Iterator object โดยตรง

Iterables ใน JavaScript

ข่าวดีคือ JavaScript มี Iterables ที่ built-in มาให้เราใช้งานมากมาย เช่น:

  • Arrays
  • Strings
  • Maps
  • Sets
  • Arguments object
  • NodeLists (DOM)
  • Generators (ที่เราเรียนไปในบทที่แล้ว)

นั่นหมายความว่าเราสามารถใช้ for...of loop กับ object เหล่านี้ได้โดยตรง

ตัวอย่าง: ใช้ for...of loop กับ Array และ String

const myArray = [4, 5, 6];
for (const value of myArray) {
  console.log(value); // 4, 5, 6
}

const myString = "Hello";
for (const char of myString) {
  console.log(char); // H, e, l, l, o
}

กรณีใช้งานจริง: Data Streaming

Iterators และ Iterables มีประโยชน์อย่างมากในการจัดการกับ data streaming หรือการประมวลผลข้อมูลทีละส่วน ยกตัวอย่างเช่น การอ่านไฟล์ขนาดใหญ่ทีละบรรทัด

ตัวอย่าง (จำลอง): สร้าง Iterable ที่จำลองการอ่านข้อมูลจากไฟล์ทีละบรรทัด

const fileReader = {
  lines: [
    "This is line 1.",
    "This is line 2.",
    "This is line 3."
  ],
  [Symbol.iterator]: function() {
    let index = 0;
    const lines = this.lines;
    return {
      next: function() {
        if (index < lines.length) {
          return { value: lines[index++], done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

for (const line of fileReader) {
  console.log(line);
}

แม้ว่าตัวอย่างนี้จะเป็นเพียงการจำลอง แต่แนวคิดนี้สามารถนำไปประยุกต์ใช้กับการอ่านไฟล์จริงๆ ได้ โดยใช้ Node.js หรือ Fetch API

ข้อผิดพลาดที่พบบ่อย

  • ลืม Implement Symbol.iterator: ถ้าคุณพยายามใช้ for...of loop กับ object ที่ไม่ได้ Implement Symbol.iterator คุณจะได้รับ error: "TypeError: object is not iterable"
  • Iterator ไม่สิ้นสุด: ถ้า Iterator ของคุณไม่เคย return done: true for...of loop จะทำงานไปเรื่อยๆ ไม่มีวันจบ (infinite loop)
  • Scope ของ index: ระวังเรื่อง scope ของตัวแปร index ใน Iterator ถ้าคุณไม่ได้ประกาศ index ภายใน function scope ของ Symbol.iterator คุณอาจเจอปัญหา unexpected behavior ได้

สรุป

Iterators และ Iterables เป็นแนวคิดพื้นฐานที่สำคัญในการทำความเข้าใจการวนซ้ำใน JavaScript Iterators กำหนดวิธีการเข้าถึงข้อมูลทีละส่วน ส่วน Iterables กำหนดวิธีการสร้าง Iterators การใช้ for...of loop ช่วยให้เราวนซ้ำข้อมูลจาก Iterables ได้อย่างง่ายดาย และ JavaScript มี Iterables ที่ built-in มาให้เราใช้งานมากมาย

ในบทต่อไป เราจะไปดู Modules Patterns โดยเริ่มจาก Revealing Module Pattern กันครับ

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service