Symbol.iterator dalam Javascript

Ini adalah artikel singkat namun bermanfaat untuk pengembang masa depan pada iterator Javascript.


gambar


Sebelum kita belajar tentang iterator di js, ingat apa itu Simbol :


Simbol adalah pengidentifikasi unik dan tidak berubah. Dibuat menggunakan fungsi Symbol (), juga dapat diberi label Symbol ('foo'). Simbol dengan label yang sama tidak sama satu sama lain, dan secara umum, simbol apa pun tidak sama satu sama lain (ingat tentang keunikan).

Ada simbol sistem seperti Symbol.iterator , Symbol.toPrimitive dan lainnya. Karakter sistem digunakan oleh bahasa itu sendiri, tetapi kita juga dapat menggunakannya untuk mengubah perilaku default beberapa objek.


Simbol adalah bagian dari spesifikasi es6, jadi mereka tidak didukung yaitu, sama sekali ( caniuse ).


Tentang Symbol.iterator


Pada dasarnya, simbol ini digunakan oleh bahasa dalam ... for loop saat iterasi properti. Itu juga dapat digunakan secara langsung dengan tipe data bawaan:


const rangeIterator = '0123456789'[Symbol.iterator](); console.log(rangeIterator.next()); // {value: "0", done: false} console.log(rangeIterator.next()); // {value: "1", done: false} console.log(rangeIterator.next()); // {value: "2", done: false} ... console.log(rangeIterator.next()); // {value: "9", done: false} console.log(rangeIterator.next()); // {done: true} 

Contoh ini berfungsi dengan string, karena String.prototype memiliki iterator ( spec ) sendiri. Daftar jenis iterable di js: String, Array, TypedArray, Map, Set.
Selain loop, javascript menggunakan Symbol.iterator dalam konstruksi berikut: operator spread, hasil , tugas penataan .


Memanggil [Symbol.iterator] () mengembalikan antarmuka iterator yang terlihat seperti ini:


 Iterator { next(); //    return(); //   throw(); //   } 

Metode .next (), .return (), .throw () mempersiapkan (maka kita akan melihat caranya) dan mengembalikan objek dari formulir:


 { value - ,   done -    } 

Metode .return () dan .throw () digunakan, misalnya, ketika iterasi berakhir sebelum waktunya. Anda dapat membaca lebih lanjut tentang mereka di spec ecmascript .


Menggunakan Symbol.iterator dalam strukturnya


Sebagai contoh, mari kita buat struktur kita sendiri, yang dapat diulang menggunakan untuk ... dan juga melihat penggunaan Symbol.iterator dengan konstruksi bahasa yang disebutkan di atas.


Bayangkan kita memiliki rute yang dilewati beberapa stasiun, dan kita ingin pergi sepanjang rute dan melakukan sesuatu dengan setiap stasiun, misalnya, menampilkannya di konsol.


Buat kelas Rute :


 class Route { stations; //      constructor(stations) { this.stations = stations; } //     id get(idx) { return this.stations[idx]; } //   [Symbol.iterator]() { return new RouteIterator(this); //   } } 

Seperti yang Anda lihat, Route kami mengimplementasikan metode Symbol.iterator , jadi Route adalah entitas yang dapat diubah ( spek ), yang berarti kita dapat melewatinya menggunakan untuk ... dari (setelah kita melihat implementasi RouteIterator ).


Metode [Symbol.iterator] () akan dipanggil sebanyak yang telah dipanggil. Artinya, jika beberapa siklus mencoba melalui rute satu demi satu, maka [Symbol.iterator] () akan dipanggil untuk setiap siklus, jadi untuk setiap panggilan kami membuat instance baru RouteIterator .


Sekarang mari kita mengenal RouteIterator itu sendiri. Kelas ini mengimplementasikan antarmuka iterator untuk entitas Route . Mari kita melihatnya:


 class RouteIterator { _route; //     _nextIdx; //    constructor(route) { this._route = route; this._nextIdx = 0; } next() { if (this._nextIdx === this._route.stations.length) { return { done: true } //     } const result = { value: this._route.get(this._nextIdx), done: false } this._nextIdx++; return result; } } 

Di kelas ini, kami memiliki akses ke koleksi iterable (properti rute ), serta nextIdx adalah pointer ke nilai berikutnya dalam koleksi kami.


Metode next () pertama-tama memeriksa apakah rute telah selesai, dan jika sudah selesai, mengembalikan bahwa iterasi sudah selesai. Kalau tidak, kita mengambil nilai berikutnya dalam pengumpulan rute , katakan bahwa iterasi tidak selesai, pindahkan pointer dan kembalikan hasilnya.


Sekarang kita bisa melalui pengumpulan rute melalui untuk ... dari :


 const route = new Route(['', '', '']) for (let item of route) { console.log(item); } 

Kode ini akan mencantumkan stasiun yang kami lewati ke Rute .


Sekarang kita akan melalui stasiun menggunakan generator fungsi:


 function* gen() { yield* route; return 'x'; //        .next() } const g = gen(); g.next() // {value: "", done: false} g.next() // {value: "", done: false} g.next() // {value: "", done: false} g.next() // {value: 'x', done: true} g.next() // {value: undefined, done: true} 

Symbol.iterator digunakan untuk restrukturisasi :


 const [a, b, c] = route; // a - "" // b - "" //  - "" 

dan dengan operator spread :


 function test(a, b, c) { console.log(a, b, c) } test(…route) // "" "" "" 

Hasil


Kami menciptakan kelas kami, membuatnya dapat diubah dan digunakan dengan konstruksi javascript. Terima kasih atas perhatiannya =).


Material


Tidak mungkin untuk sepenuhnya menguasai materi baru hanya dalam satu artikel, jadi di sini ada beberapa tambahan:
Tentang pola iterator dari buku Guru Refactoring
Tentang Simbol dari buku Ilya Kantor dan di MDN

Source: https://habr.com/ru/post/id481548/


All Articles