Kodealgo

Iterables JavaScript

Pernah menemukan pesan kesalahan TypeError: x is not iterable? Pesan tersebut akan sedikit membingungkan jika kita belum memahami apa itu iterable.

Dengan mehamai iterable, kita tidak hanya bisa memahami pesan kesalahan itu saja, tapi juga memahami:

  • Kapan menggunakan for...of.
  • Kapan menggunakan spread operator (...).
  • Membuat objek yang tidak bisa diulang menggunakan for...of menjadi bisa, tanpa muncul pesan kesalah seperti di atas.

Mari kita pelajari.

  1. Apa Itu Iterable
  2. Protokol Iterasi
    1. Protokol Iterable
    2. Protokol Iterator
  3. Kesimpulan

Apa Itu Iterable?

JavaScript mendukung protokol dimana struktur data seperti array dapat diiterasi secara berurutan menggunakan for..of atau disebarkan menggunakan spread operator .... Objek atau struktur data yang mendukung fungsi tersebut disebut iterable.

Objek tersebut tidak mungkin mendukung fungsi tersebut tanpa protokol iterasi, yaitu protokol iterable dan iterator. Jadi, iterable adalah stuktur data atau objek yang mengimplementasikan protokol iterasi.

Protokol Iterasi

Protokol iterasi ditambahkan pada ECMAScript 2015, protokol-protokol ini dapat diimplementasi oleh objek apa pun asalkan mengikuti beberapa konvensi.

Protokol iterasi terdiri dari 2 protokol:

  1. Iterable
  2. Iterator

1. Protokol Iterable

Protokol iterable memungkinkan objek JavaScript menyesuaikan perilaku iterasinya, seperti nilai apa yang diiterasi dalam sebuah for...of. Array dan Map secara default iterable, sedangkan Objek tidak.

Agar iterable, sebuah objek harus mengimplementasikan method bernama @@iterator yang dapat diakses melalui konstanta Symbol.iterator, method ini dapat berupa fungsi biasa atau fungsi generator.

Fungsi ini harus mengembalikan objek yang sesuai dengan protokol iterator (dibahas di bawah).

Mari kita buktikan bahwa Array memiliki method @@iterator, sedangkan objek tidak:

const myNumbers = [1, 2, 3];
typeof myNumbers[Symbol.iterator]; // function

const myRange = { from: 1, to: 3 };
typeof myRange[Symbol.iterator]; // undefined

Oleh karena itu, kita bisa mengulang array menggunakan for...of sedangkan objek tidak:

const myNumbers = [1, 2, 3];
for (const number of myNumbers) {
  console.log(number);
}
/* output:
1
2
3
*/

const myRange = { from: 1, to: 3 };
for (const range of myRange) {
  console.log(range);
}
// output: TypeError: myRange is not iterable

Begitu juga dengan spread operator (...):

const myNumbers = [1, 2, 3];
[...myNumbers]; // [ 1, 2, 3 ];

const myRange = { from: 1, to: 3 };
[...myRange]; // TypeError: myRange is not iterable

Mari kita implementasikan protokol iterable ke dalam objek myRange:

const myRange = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {},
};

[...myRange]; // TypeError: Result of the Symbol.iterator method is not an object

Sekarang pesan kesalahnnya berubah, kita telah mengimplementasikan protokol iterable, method ini harus mengembalikan sebuah objek berisi method next() sesuai dengan protokol iterator.

2. Protokol Iterator

Protokol iterator mendefinisikan cara untuk menghasilkan urutan nilai. Objek termasuk iterator ketika mengimplementasikan method next() yang menyembalikan objek { done: boolean, value: nilai }.

Properti done harus memiliki nilai false ketika masih ada nilai berikutnya yang akan diulang, sedangkan nilai adalah nilai yang dikembalikan selama iterasi.

Jika tidak ada nilai berikutnya, properti done harus bernilai true lalu properti value dapat dihilangkan atau diinisialisasi dengan nilai undefined.

Mari kita implementasikan ini pada objek sebelumnya:

const myRange = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {
    return {
      current: this.from,
      last: this.to,
      next() {
        if (this.current <= this.last) {
          return {
            done: false,
            value: this.current++,
          };
        } else {
          return {
            done: true,
            value: undefined,
          };
        }
      },
    };
  },
};

Objek myRange sekarang iterable, ketika diulang menggunakan for...of objek ini akan mengembalikan angka berurutan dari from sampai to (1, 2, 3), urutan nilai yang dikembalikan ditentukan pada method next(), mari kita coba:

// ...

for (const range of myRange) {
  console.log(range);
}
/* output:
1
2
3
*/

[...myRange]; // [ 1, 2, 3 ]

Kesimpulan

Objek atau struktur data menjadi iterable jika mengimplementasikan protokol iterasi. Objek iterable dapat diulang menggunakakn for...of, disebarkan melalui spread operator (...) dan sebagainya.

Ada beberapa struktur data yang secara default iterable diantaranya String, Array, Map, Set dan lain sebagainya. Kita juga dapat membuat struktur data atau objek agar iterable dengan mengimplementasikan protokol iterasi.