Iterables

...

Iterables

Iterable obyektlar — bu massivlarning umumiylashtirilgan tushunchasi bo‘lib, bu konsept har qanday obyektni for..of siklida ishlatiladigan qiladigan usuldir.

Albatta, massivlar iterable sanaladi. Ammo ko‘plab boshqa o‘rnatilgan obyektlar ham iterable. Masalan, satrlar ham iterable hisoblanadi.

Agar obyekt texnik jihatdan massiv bo‘lmasa, ammo nimaningdir to‘plami (list, set) ko‘rinishida bo‘lsa, for..of sikli orqali uni iteratsiya qilish mumkin. Keling, bu qanday ishlashini ko‘rib chiqaylik.

Symbol.iterator

Iterables tushunchasini tushunib olish uchun o‘zimiz birini yaratib ko‘ramiz.

Masalan, bizda massiv emas, lekin for..of uchun mos ko‘rinadigan obyekt mavjud, masalan, raqamlar oralig‘ini ifodalovchi obyekt:

let range = {
  from: 1,
  to: 5,
};
 
// Biz xohlaymizki, `for..of` shu tarzda ishlasin:
// for(let num of range) ... num=1,2,3,4,5

for..of ishlashi uchun range obyektini iterable qilish kerak, buning uchun Symbol.iterator deb nomlangan maxsus metod qo‘shamiz.

for..of boshlanganda ushbu metodni bir marta chaqiradi (topilmasa xatolik yuz beradi). Bu metod iteratorni qaytarishi kerak – u next metodiga ega obyekt bo‘lishi kerak. Keyinchalik for..of faqat shu qaytarilgan obyekt bilan ishlaydi.

for..of yangi qiymat so‘raganda, bu obyektdan next() metodini chaqiradi.

next() ning natijasi {done: Boolean, value: any} ko‘rinishida bo‘lishi kerak, bu yerda done=true bo‘lsa, iteratsiya tugagan bo‘ladi, aks holda value keyingi qiymat hisoblanadi.

Mana range ning to‘liq kodiga sharhlar bilan birga qaraymiz:

let range = {
  from: 1,
  to: 5,
};
 
// 1. Dastlab `for..of` chaqirilganda bu ishga tushadi
range[Symbol.iterator] = function () {
  // ...iterator obyektini qaytaradi:
  // 2. `for..of` bundan keyin faqat iterator obyekt bilan ishlaydi
  return {
    current: this.from,
    last: this.to,
 
    // 3. `next()` har bir iteratsiya davomida chaqiriladi
    next() {
      // 4. Qiymatni obyekt sifatida qaytarishi kerak: {done:.., value:...}
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    },
  };
};
 
// Endi ishlaydi!
for (let num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}

E’tibor bering, iterablelarning asosiy xususiyati — vazifalarni ajratish.

range ning o‘zi next() metodiga ega emas. Aksincha, range[Symbol.iterator]() chaqirilganda boshqa bir obyekt yaratiladi, bu obyekt iteratsiya uchun qiymatlar yaratadi.

Iterator obyekti iteratsiya qilinayotgan obyekt bilan alohida hisoblanadi.

Texnik jihatdan ularni birlashtirishimiz va kodni sodda qilish uchun range ni o‘zini iterator sifatida ishlatishimiz mumkin:

let range = {
  from: 1,
  to: 5,
 
  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },
 
  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  },
};
 
for (let num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}

Endi range[Symbol.iterator]() metodi range obyektini o‘zini qaytaradi. U kerakli next() metodiga ega va iteratsiya jarayonini this.current da saqlab boradi. Bu qisqa, ammo ba’zan bu yaxshi.

Kamchiligi shundaki, endi bir vaqtda ikki xil for..of siklini ishga tushirish imkonsiz, chunki faqat bitta iterator mavjud – bu obyektning o‘zi. Ammo bitta obyektni bir vaqtda ikki xil sikl bilan iteratsiya qilish juda kam holatda kerak bo‘ladi, hattoki asinxron holatlarda ham.

Cheksiz iteratsiyalar

Cheksiz iteratsiyalar ham mumkin. Masalan, range.to = Infinity bo‘lsa, range cheksiz bo‘ladi. Yoki cheksiz tasodifiy raqamlar ketma-ketligini yaratadigan obyekt qilishingiz mumkin.

Albatta, bunday obyekt ustida for..of sikli cheksiz bo‘ladi. Ammo biz uni break orqali to‘xtatishimiz mumkin.

Satrlar iterable

Massivlar va satrlar o‘rnatilgan iterable obyektlardir.

Masalan, satrda for..of har bir belgi ustida ishlaydi:

for (let char of 'test') {
  console.log(char); // t, e, s, t
}

Iteratsiyani qo‘lda chaqirish

Iteratsiyani to‘g‘ridan-to‘g‘ri for..of yordamida emas, balki qo‘lda boshqarish ham mumkin. Masalan:

let str = 'Hello';
let iterator = str[Symbol.iterator]();
 
while (true) {
  let result = iterator.next();
  if (result.done) break;
  console.log(result.value); // Belgilarni birma-bir chiqaradi
}

Bu kamdan-kam hollarda kerak bo‘ladi, lekin jarayon ustidan to‘liq nazoratni olish uchun foydali.

Iterable va array-likes

Iterables — bu Symbol.iterator metodini amalga oshiruvchi obyektlar. Array-likes esa indekslarga va uzunlikka ega obyektlar bo‘lib, ular massivlarga o‘xshab ko‘rinadi.

Array.from

Array.from metodi iterable yoki array-like obyektlarni massivga aylantirish uchun ishlatiladi.

Misol:

let arrayLike = {
  0: 'Hello',
  1: 'World',
  length: 2,
};
 
let arr = Array.from(arrayLike);
console.log(arr.pop()); // World

Xulosa

  • Iterable obyektlar for..of siklida ishlatilishi mumkin.
  • Array.from metodi iterable yoki array-like obyektlarni haqiqiy massivga aylantiradi.

Ushbu sahifada

GitHubda tahrirlash