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.
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:
- Iterable
- 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.