IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur54/65-dars21 daqiqa
Mundarija (35)

JavaScript iterator helpers (ES2025): map, filter, take dangasa ishlaydi

Qisqacha: ES2025 dan boshlab har bir o'rnatilgan iteratorda — massiv values() si, Map/Set iteratorlari, generatorlar — massivdagiga o'xshash metodlar bor: map, filter, take, drop, flatMap, reduce, toArray, some, every, find, forEach. Ular oraliq massiv yasamaydi va dangasa ishlaydi: qiymatlar zanjir bo'ylab bittadan o'tadi va faqat so'ralganda. Shuning uchun take(3) cheksiz ketma-ketlikda ham ishlaydi. O'z iteratoringizga bu metodlarni Iterator.from() beradi.

Bu darsda

  • Iterator helpers zanjirini yozasiz: menyu.values().filter(...).map(...).toArray().
  • Massiv zanjiri va iterator zanjiri callback'larni qaysi tartibda chaqirishini ko'rasiz va farqini o'lchaysiz.
  • O'zgartiruvchi (map, filter, take, drop, flatMap) va yakunlovchi (toArray, reduce, find…) metodlarni ajratasiz.
  • Iterator.from() bilan o'z iteratoringizga helper'larni qo'shasiz.
  • Brauzer va Node qo'llovini (Baseline) tekshirib, massiv yoki iterator helper'ni ongli tanlaysiz.

Oldin bilishingiz kerak: Metod zanjiri va ma'lumot pipeline, Generator funksiyalar, Generatorlar chuqur, Map, Callback imzosi.

1. Nega bu kerak?

Metod zanjiri darsida va'da bergan edik: "2025-yilda JavaScript'ga dangasa zanjir ham qo'shildi — buyurtmalar.values().filter(...).take(3).toArray()". Bugun shu va'dani bajaramiz.

Avval massiv zanjirining ikki noqulayligini eslaymiz.

Birinchi: u hammasini qiladi. «Bahor»da bugun 1000 ta buyurtma bo'ldi. Jasur aka so'radi: "30 000 so'mdan qimmat birinchi uchta buyurtma qaysi?" Massiv bilan:

js
const narxlar = [5000, 28000, 35000, 30000, 63000];
const buyurtmalar = Array.from({ length: 1000 }, (_, i) => ({
  id: i + 1,
  summa: narxlar[i % 5],
}));

let tekshirildi = 0;
const birinchiUch = buyurtmalar
  .filter((b) => {
    tekshirildi++;
    return b.summa > 30000;
  })
  .map((b) => b.id)
  .slice(0, 3);

console.log(birinchiUch); // [ 3, 5, 8 ]
console.log(tekshirildi); // 1000

Javob uchun sakkizta buyurtmani ko'rish kifoya edi. filter esa mingtasini tekshirdi, 400 ta mos keluvchidan yangi massiv yasadi, map ularning hammasidan yana bitta massiv yasadi. slice esa oxirida 397 tasini tashlab yubordi.

Ikkinchi: u faqat massivda. Map, Set, generator — massiv emas. Ularda filter yo'q. Avval [...] bilan massivga aylantirish kerak, cheksiz generatorni esa umuman aylantirib bo'lmaydi (Generator funksiyalar).

Iterator helpers ikkala muammoni yopadi. O'xshatish: konveyer. Massiv zanjiri — har bosqich butun partiyani tugatib, keyingi bosqichga yashik bilan uzatadigan sex. Iterator zanjiri — konveyer lentasi: har mahsulot bittadan barcha bosqichlardan o'tadi, va "uchta tayyor" bo'lishi bilan lenta to'xtaydi.

2. Birinchi zanjir

2.1 values() dan boshlanadi

js
const menyu = new Map([
  ["osh", 35000],
  ["lag'mon", 28000],
  ["manti", 30000],
  ["ko'k choy", 5000],
]);

const arzonlar = menyu
  .entries()
  .filter(([taom, narx]) => narx < 31000)
  .map(([taom]) => taom);

console.log(arzonlar);
console.log(arzonlar.toArray());

Konsolda:

text
Object [Iterator Helper] {}
[ "lag'mon", 'manti', "ko'k choy" ]

Qatorma-qator:

  1. menyu.entries() — Map iteratori, u [kalit, qiymat] juftliklarini beradi (Iteratsiya protokoli).
  2. .filter(...) — massivniki emas, iteratorning metodi. U massiv emas, yangi iterator qaytaradi.
  3. .map(...) — yana yangi iterator.
  4. console.log(arzonlar) — Object [Iterator Helper] {}. Bu hali natija emas, faqat "tayyor zanjir". Hech bir callback hali chaqirilmagan!
  5. .toArray() — zanjirni ishga tushiradi va qiymatlarni massivga yig'adi.

Iterator helpers (inglizcha "iterator yordamchilari") — ES2025 standartida iteratorlarga qo'shilgan metodlar to'plami. Ular hamma o'rnatilgan iteratorlarning umumiy ajdodida — Iterator.prototype da turadi (Prototip zanjiri). Shuning uchun massiv, Map, Set, satr iteratorlari va generatorlar — hammasi ularni meros oladi.

2.2 Massivdan to'g'ridan-to'g'ri — yo'q

js
const narxlar = [35000, 28000];
narxlar.take(1);

Konsolda:

text
TypeError: narxlar.take is not a function

Tarjimasi: "narxlar.take — funksiya emas". Massivning o'zi iterator emas — unda take yo'q. Iterator helper kerak bo'lsa, avval iterator oling: narxlar.values().take(1). map va filter esa massivda ham bor — lekin bu boshqa metodlar: massivniki darhol massiv qaytaradi, iteratorniki — dangasa iterator.

Tekshirib ko'ring: new Set(["osh", "manti"]).values().map((t) => t.length) nima qaytaradi? .toArray() qo'shilsa-chi?

Javob

Birinchisi — Object [Iterator Helper] {}: zanjir tayyor, lekin hali ishlamagan. .toArray() bilan — [ 3, 5 ]. Set iteratori ham Iterator.prototype dan meros oladi, shuning uchun unda ham map bor — [...to'plam] bilan massivga aylantirish shart emas.

3. Dangasa: konveyer tartibi

3.1 Callback'lar qaysi tartibda chaqiriladi?

Ikkala zanjirga "gapiradigan" callback'lar beramiz:

js
const taomlar = [
  { nom: "osh", narx: 35000 },
  { nom: "choy", narx: 5000 },
  { nom: "manti", narx: 30000 },
];

const katta = (t) => {
  console.log(`filter: ${t.nom}`);
  return t.narx > 10000;
};
const nomi = (t) => {
  console.log(`map: ${t.nom}`);
  return t.nom;
};

taomlar.filter(katta).map(nomi);
console.log("---");
taomlar.values().filter(katta).map(nomi).toArray();

Konsolda:

text
filter: osh
filter: choy
filter: manti
map: osh
map: manti
---
filter: osh
map: osh
filter: choy
filter: manti
map: manti

Massiv zanjiri — bosqichma-bosqich: avval filter hamma elementni o'tkazdi, keyin map natijani. Iterator zanjiri — elementma-element: osh filter dan o'tib, darhol map ga bordi; choy filter da to'xtadi va map ga yetmadi; keyin manti. Bu Generator funksiyalar darsidagi "oshxona va ofitsiant"ning o'zi.

3.2 Qadamma-qadam

Keyingi ni bosing va next() so'rovi zanjir bo'ylab qanday "orqaga" yurishini kuzating: oxirgi bo'g'in oldingisidan so'raydi, u esa o'zidan oldingisidan.

Dangasa hisob — o'tgan darslardagi atama: qiymat faqat so'ralganda hisoblanadi. Zanjir yasash — tekin; ish faqat iste'molchi (next(), toArray(), for...of) so'raganda boshlanadi.

3.3 O'lchaymiz: 1000 buyurtmadan birinchi uchta

«Nega bu kerak?» bo'limidagi savolni iterator zanjiri bilan:

js
const narxlar = [5000, 28000, 35000, 30000, 63000];
const buyurtmalar = Array.from({ length: 1000 }, (_, i) => ({
  id: i + 1,
  summa: narxlar[i % 5],
}));

let tekshirildi = 0;
const birinchiUch = buyurtmalar
  .values()
  .filter((b) => {
    tekshirildi++;
    return b.summa > 30000;
  })
  .map((b) => b.id)
  .take(3)
  .toArray();

console.log(birinchiUch); // [ 3, 5, 8 ]
console.log(tekshirildi); // 8

Natija bir xil, lekin filter 1000 emas, 8 marta chaqirildi. take(3) uchinchi qiymatni olgach, zanjirga "boshqa kerak emas" dedi va hamma bo'g'in to'xtadi. Oraliq massivlar ham yo'q.

Vaqtda bu qanday ko'rinadi? Million buyurtmada ikki vazifani o'lchadik: "birinchi uchta" va "hammasining summasi" (filter → map → reduce):

1 000 000 buyurtma: massiv va iterator zanjiri
  • Massiv: birinchi 3hammasini filtrlaydi43,7 ms
  • Iterator: birinchi 30,1 ms dan kam0 ms
  • Massiv: hammasi2 oraliq massiv65,4 ms
  • Iterator: hammasioraliq massivsiz81,2 ms

Manba: O'lchov: Node 24.21, Windows 11, performance.now, 9 o'lchovning medianasi, 2026-10-04

Ikki xulosa. "Birinchi N ta" yoki "birinchi mos keluvchi" kerak bo'lsa — iterator zanjiri yuzlab marta tezroq: u ishni erta to'xtatadi. Hamma element kerak bo'lsa — oddiy massiv zanjiri biroz tezroq: har qiymatning zanjir bo'ylab "so'rov-javob" yurishi ham vaqt oladi. Dangasalik tekin emas — u faqat ishni tejash mumkin bo'lganda yutadi.

Tekshirib ko'ring: buyurtmalar.values().filter(...).map(...) zanjirini yasab, toArray() ni chaqirmasak, tekshirildi nechaga teng bo'ladi?

Javob

0. Zanjir yasash hech qanday callback'ni chaqirmaydi — u faqat iteratorlarni bir-biriga ulaydi. Callback'lar faqat kimdir qiymat so'raganda (next(), toArray(), for...of, spread) ishlaydi.

4. Metodlar oilasi

4.1 Ikki tur: zanjirni davom ettiruvchi va tugatuvchi

O'zgartiruvchi (yangi iterator) Nima qiladi
map(fn) har qiymatni fn bilan o'zgartiradi
filter(fn) fn rost qaytarganlarini o'tkazadi
take(n) birinchi n tasini beradi, keyin to'xtaydi
drop(n) birinchi n tasini tashlab, qolganini beradi
flatMap(fn) fn qaytargan iterable'ni ochib, bittadan beradi
Yakunlovchi (natija) Nima qaytaradi
toArray() hamma qiymatlar massivi
reduce(fn, boshlang'ich) bitta yig'ma qiymat
some(fn), every(fn) true / false
find(fn) birinchi mos qiymat yoki undefined
forEach(fn) undefined (faqat yon ta'sir uchun)

O'zgartiruvchilar zanjir quradi va hech narsa hisoblamaydi. Yakunlovchilar zanjirni "yoqadi" va iteratorni oxirigacha (yoki javob topilguncha) aylanadi. Massivdagi reduce, find/some bilan ma'nosi bir xil. some, every va find erta chiqadi — javob ma'lum bo'lishi bilan to'xtaydi.

js
const menyu = new Map([
  ["osh", 35000],
  ["lag'mon", 28000],
  ["manti", 30000],
  ["ko'k choy", 5000],
]);

console.log(menyu.values().reduce((a, b) => a + b, 0)); // 98000
console.log(menyu.keys().some((t) => t === "osh")); // true
console.log(menyu.keys().find((t) => t.startsWith("m"))); // manti
console.log(menyu.keys().drop(1).take(2).toArray());

Konsolda:

text
98000
true
manti
[ "lag'mon", 'manti' ]

drop(1).take(2) — "birinchisini o'tkazib, keyingi ikkitasi". Massivdagi slice(1, 3) ning dangasa egizagi — sahifalashda qulay: drop(sahifa * hajm).take(hajm).

4.2 Callback imzosi boshqacha

Callback imzosi darsida massiv metodlari callback'ni (element, index, array) bilan chaqirishini ko'rgan edik. Iterator helper'larda imzo boshqa:

js
const natija = ["osh", "manti"]
  .values()
  .map((taom, i, uchinchi) => `${i}: ${taom}, ${uchinchi}`)
  .toArray();

console.log(natija);

Konsolda:

text
[ '0: osh, undefined', '1: manti, undefined' ]

Ikkinchi argument — hisoblagich (0, 1, 2…): "nechanchi qiymat". Uchinchi argument yo'q: iteratorda "butun massiv" degan narsa yo'q — u faqat navbatdagisini biladi. Massiv kodini iteratorga ko'chirganda (x, i, arr) => arr... ishlatilgan joylarni tekshiring.

4.3 flatMap — faqat iterable qaytaring

js
const buyurtma = ["osh", "manti"];
const ikkitadan = buyurtma
  .values()
  .flatMap((t) => [t, t])
  .toArray();
console.log(ikkitadan); // [ 'osh', 'osh', 'manti', 'manti' ]

flatMap callback'i iterable (massiv, Set, generator) qaytarishi kerak. Massivdagi flatMap (flat, flatMap) oddiy qiymatni ham qabul qiladi, iteratorniki esa — yo'q. Bitta istisno — satr: u iterable bo'lsa ham rad etiladi. Satrni harflarga bo'lib yuborish ko'pincha xato bo'lgani uchun standart uni ataylab taqiqlagan. Xabari «Ko'p uchraydigan xatolar» bo'limida.

Tekshirib ko'ring: ["a", "b", "c"].values().map((x, i) => x + i).toArray() nima qaytaradi?

Javob

[ 'a0', 'b1', 'c2' ]. Ikkinchi argument — hisoblagich, u 0 dan boshlanadi. Bu yerda u massiv indeksiga teng chiqdi, lekin filter dan keyingi map da farq qiladi: hisoblagich map ga yetib kelgan qiymatlarni sanaydi, asl massivdagi o'rinni emas.

5. Cheksiz ketma-ketliklar bilan

Iterator helpers'ning eng kuchli joyi — cheksiz generatorlar. Generator funksiyalar darsidagi navbat chiptalarini eslang:

js
function* chiptalar() {
  let raqam = 1;
  while (true) {
    yield raqam++;
  }
}

const omadli = chiptalar()
  .filter((r) => r % 7 === 0)
  .map((r) => `Chipta №${r} — bepul choy`)
  .take(3)
  .toArray();

console.log(omadli);

Konsolda:

text
[
  'Chipta №7 — bepul choy',
  'Chipta №14 — bepul choy',
  'Chipta №21 — bepul choy'
]

Aksiya: har yettinchi chipta — bepul choy. Cheksiz ketma-ketlikdan dastlabki uchta omadli raqam olindi. Generator 21 marta so'raldi va to'xtadi. Generator funksiyalar darsida buning uchun o'z birinchiN generatorimizni yozgan edik — endi u tayyor: take.

Diqqat: take siz cheksiz zanjirga toArray(), reduce() yoki forEach() — dastur abadiy ishlaydi. filter ham xavfli bo'lishi mumkin: chiptalar().filter((r) => r < 0).take(1) — hech qachon mos qiymat topilmaydi, take esa birinchisini kutaveradi. some va find faqat javob topilganda to'xtaydi.

6. Ichidan: helper'ni generator bilan yozamiz

map va filter darslaridan beri odatimiz bor: metodni ishlatishdan oldin uni o'zimiz yozib ko'ramiz. Generator bilan bu juda qisqa:

js
function* dangasaFiltr(iterable, shart) {
  let hisob = 0;
  for (const qiymat of iterable) {
    if (shart(qiymat, hisob++)) {
      yield qiymat;
    }
  }
}

function* birinchilar(iterable, n) {
  if (n <= 0) return;
  let berildi = 0;
  for (const qiymat of iterable) {
    yield qiymat;
    if (++berildi === n) return;
  }
}

const juftlar = dangasaFiltr([1, 2, 3, 4, 5, 6], (x) => x % 2 === 0);
console.log([...birinchilar(juftlar, 2)]); // [ 2, 4 ]

dangasaFiltr — filter ning dangasa nusxasi, birinchilar — take niki. Ikkalasi ham generator: qiymatni bittadan oladi, bittadan beradi, hech narsa yig'maydi. Tayyor helper'lar ichida xuddi shu mantiq, faqat ular zanjir ko'rinishida yoziladi (x.filter().take()), bizniki esa ichma-ich chaqiruv (birinchilar(dangasaFiltr(...))). Zanjir o'qishga qulayroq — standartga aynan shuning uchun qo'shildi.

++berildi === n — avval oshiradi, keyin solishtiradi. Tekshiruv yield dan keyin: n-qiymat berilgach, generator boshqa so'ramay tugaydi (Generator funksiyalar darsidagi 3-mashq).

7. Iterator.from() — o'z iteratoringizga helper'lar

7.1 Qo'lda yozilgan iteratorda metod yo'q

O'z iterable obyektingizni yasash darsidagi qo'lda yozilgan oraliq ni eslang. Uning iteratori — oddiy obyekt, u Iterator.prototype dan meros olmaydi:

js
function oraliq(boshi, oxiri) {
  return {
    [Symbol.iterator]() {
      let joriy = boshi;
      return {
        next() {
          return joriy < oxiri
            ? { value: joriy++, done: false }
            : { value: undefined, done: true };
        },
      };
    },
  };
}

oraliq(1, 6)[Symbol.iterator]().map((x) => x * 2);

Konsolda:

text
TypeError: oraliq(...)[Symbol.iterator](...).map is not a function

Generator bilan yozilgan oraliq da bu muammo yo'q — generatorlar Iterator.prototype dan meros oladi.

7.2 Iterator.from o'rab beradi

Iterator.from(x) — iterable'ni yoki next() li obyektni oladi va helper'lari bor haqiqiy iterator qaytaradi:

js
function oraliq(boshi, oxiri) {
  return {
    [Symbol.iterator]() {
      let joriy = boshi;
      return {
        next() {
          return joriy < oxiri
            ? { value: joriy++, done: false }
            : { value: undefined, done: true };
        },
      };
    },
  };
}

const toqlar = Iterator.from(oraliq(1, 10))
  .filter((x) => x % 2 === 1)
  .toArray();
console.log(toqlar); // [ 1, 3, 5, 7, 9 ]

const narxlar = Iterator.from([35000, 28000]).map((n) => n / 1000);
console.log(narxlar.toArray()); // [ 35, 28 ]

Iterator — o'rnatilgan global obyekt: barcha iteratorlarning umumiy "ajdodi". Iterator.from unga o'z iterable'ingizni ulaydi. Massiv yoki Set uchun ham ishlaydi (Iterator.from([..]) ≈ [..].values()), lekin ularning o'zida values() bor — Iterator.from asosan o'z yasagan obyektlaringiz va kutubxonalardan kelgan iteratorlar uchun.

Tekshirib ko'ring: Generatorlar chuqur darsidan keyin VazifalarRoyxati da *[Symbol.iterator]() generator metodi bor. holat.vazifalar[Symbol.iterator]().filter((v) => !v.bajarildi) ishlaydimi, yoki Iterator.from kerakmi?

Javob

Ishlaydi, Iterator.from shart emas: generator metod qaytargan obyekt — generator, u esa Iterator.prototype dan helper'larni meros oladi. Iterator.from(holat.vazifalar) ham to'g'ri — u royxatning [Symbol.iterator]() ini chaqirib, o'sha generatorni qaytaradi. O'tgan darsdagi qo'lda yozilgan iterator bo'lganida esa Iterator.from kerak bo'lardi.

8. Qayerda ishlaydi: Baseline va Node

Iterator helpers — yangi imkoniyat. Ishlatishdan oldin kodingiz qayerda ishlashini o'ylang: sizning serveringizdami yoki mehmonlarning har xil telefonlaridami.

Imkoniyat Standart Brauzerlar Node 24
map, filter, take, drop, flatMap, reduce, toArray, some, every, find, forEach, Iterator.from ES2025 Chrome/Edge 122, Firefox 131, Safari 18.4 bor
Iterator.concat ES2026 Chrome/Edge 146, Firefox 147, Safari 26.4 yo'q
Iterator.zip taklif Chrome 154 da bor, Baseline emas yo'q

Baseline ma'lumotiga ko'ra, asosiy helper'lar 2025-yil 31-martdan Baseline (barcha asosiy brauzerlarda), lekin hali "widely available" (keng tarqalgan — eski qurilmalar ham yangilanib ulgurgan) emas. Bu belgi Baseline'dan 30 oy o'tib — 2027-yil oxiriga yaqin beriladi. Ya'ni bugun Safari 18.4 dan eski iPhone'larda ular ishlamaydi. Node'da esa ular 22-versiyadan bor; Node 24 da hammasini sinab ko'rdik.

Iterator.concat(a, b) — bir nechta iterable'ni ketma-ket ulaydi, ES2026 da qo'shildi va 2026-yil martidan Baseline. Lekin Node 24 da hali yo'q:

js
console.log(typeof Iterator.from); // function
console.log(typeof Iterator.concat); // undefined

Node 24 da uning o'rnini Generatorlar chuqur darsidagi yield* bosadi: function* ula(...lar) { for (const x of lar) yield* x; }. Iterator.zip esa — bir nechta iteratorni "juftlab" aylanish taklifi; xaritamizda u ES2027 ga kutilmoqda. Chrome 154 da u allaqachon bor (o'zimiz tekshirdik), lekin Baseline ma'lumotida unga hali belgi berilmagan.

Amaliy qoida:

  • Node.js'dagi kod (server, skriptlar, Node 22+) — iterator helpers'ni bemalol ishlating.
  • Ommaviy sayt — Baseline "widely available" bo'lguncha yoki ehtiyot uchun: kichik ro'yxatlarda oddiy massiv metodlari; katta yoki cheksiz ketma-ketlikda — generator va for...of (ular 2016-yildan beri hamma joyda). Yoki Babel/core-js kabi vositalar bilan polyfill — ularni 16-qismda o'rganamiz.

9. Qachon massiv, qachon iterator helper?

Vaziyat Tanlov
Kichik ro'yxat, hamma element kerak massiv metodlari — oddiy va biroz tezroq
"Birinchi N ta", "birinchi mos" katta to'plamdan iterator: values().filter().take()
Map, Set, generator ustida zanjir iterator helper — massivga aylantirmasdan
Cheksiz ketma-ketlik faqat iterator helper (take bilan)
Natijani qayta-qayta o'qish kerak massiv (toArray() bilan bir marta yig'ing)

Oxirgi qatorga e'tibor bering: iterator zanjiri ham iterator — bir martalik. Uni ikki marta aylansangiz, ikkinchisi bo'sh bo'ladi.

10. Ko'p uchraydigan xatolar

10.1 toArray() ni unutish

console.log(menyu.values().map(...)) — Object [Iterator Helper] {}. Natija emas, tayyor zanjir. Hech bir callback ishlamagan. Tuzatish: yakunlovchi metod chaqiring — toArray(), reduce(), for...of yoki spread.

10.2 Massivda take / drop ni chaqirish

narxlar.take(3) — TypeError: narxlar.take is not a function («Massivdan to'g'ridan-to'g'ri — yo'q» bo'limi). Tuzatish: narxlar.values().take(3) — yoki massivda slice(0, 3).

10.3 Zanjirni ikki marta ishlatish

js
const ikkilangan = [1, 2, 3].values().map((x) => x * 2);
console.log([...ikkilangan]); // [ 2, 4, 6 ]
console.log([...ikkilangan]); // []

Iterator — bir martalik (Iteratsiya protokoli). Xato chiqmaydi, ikkinchi natija shunchaki bo'sh. Tuzatish: natija qayta kerak bo'lsa — bir marta toArray() qilib, massivni saqlang.

10.4 flatMap dan satr qaytarish

js
const harflar = ["osh"].values().flatMap((t) => t).toArray();

Konsolda:

text
TypeError: Iterator.prototype.flatMap called on non-object

Tarjimasi: "Iterator.prototype.flatMap obyekt bo'lmagan qiymatda chaqirildi". Xabar chalg'itadi: muammo flatMap qayerda chaqirilganida emas, callback qaytargan qiymatda — "osh" satri obyekt emas. Iterator flatMap i satrni ataylab rad etadi («flatMap — faqat iterable qaytaring» bo'limi). Tuzatish: harflar kerak bo'lsa — [...t] qaytaring; satrning o'zi kerak bo'lsa — flatMap emas, map.

10.5 Bo'sh iteratorda boshlang'ichsiz reduce

[].values().reduce((a, b) => a + b) — TypeError: Reduce of a done iterator with no initial value ("tugagan iteratorni boshlang'ich qiymatsiz yig'ib bo'lmaydi"). Massivdagi reduce bilan bir xil qoida (reduce). Tuzatish: doim boshlang'ich qiymat bering — reduce((a, b) => a + b, 0).

10.6 take ga noto'g'ri son

take(-1) yoki take() — RangeError: -1 must be positive / RangeError: undefined must be positive ("musbat bo'lishi kerak"). slice manfiy sonni "oxiridan" deb tushunadi, take esa — yo'q: iteratorda "oxiri" noma'lum. Tuzatish: 0 yoki musbat son bering.

11. Mashqlar

1-mashq (oson): Arzon taomlar

«Bahor» menyusi Map da (osh 35 000, lag'mon 28 000, manti 30 000, ko'k choy 5 000). Iterator helpers bilan narxi 30 000 dan oshmaydigan taomlar nomini katta harf bilan massivga yig'ing. [...menyu] ishlatmang — entries() dan boshlang.

Yechim
js
const menyu = new Map([
  ["osh", 35000],
  ["lag'mon", 28000],
  ["manti", 30000],
  ["ko'k choy", 5000],
]);

const arzonlar = menyu
  .entries()
  .filter(([, narx]) => narx <= 30000)
  .map(([taom]) => taom.toUpperCase())
  .toArray();

console.log(arzonlar); // [ "LAG'MON", 'MANTI', "KO'K CHOY" ]

([, narx]) — destructuring'da birinchi elementni (kalitni) o'tkazib yuborish: vergul oldida nom yo'q (Massiv destructuring). Map hech qachon massivga aylanmadi — juftliklar to'g'ridan-to'g'ri filter va map dan o'tdi.

2-mashq (o'rta): Bo'sh bron vaqtlari

Bron yarim soatlik oraliqlarda: 10:00, 10:30, 11:00… Band vaqtlar — new Set(["10:00", "11:00", "11:30"]). Cheksiz function* yarimSoatlar(boshSoat) generatorini yozing ("10:00", "10:30", "11:00"… satrlarini bersin). So'ng iterator helpers bilan birinchi uchta bo'sh vaqtni oling. Soat va daqiqani satrga: `${soat}:${daqiqa === 0 ? "00" : "30"}`.

Yechim
js
function* yarimSoatlar(boshSoat) {
  for (let soat = boshSoat; ; soat++) {
    yield `${soat}:00`;
    yield `${soat}:30`;
  }
}

const band = new Set(["10:00", "11:00", "11:30"]);

const boshVaqtlar = yarimSoatlar(10)
  .filter((vaqt) => !band.has(vaqt))
  .take(3)
  .toArray();

console.log(boshVaqtlar); // [ '10:30', '12:00', '12:30' ]

for (let soat = boshSoat; ; soat++) — shartsiz for: o'rta qism bo'sh, sikl cheksiz. Generatorda bu xavfsiz — har yield da pauza. Daqiqa formulasi o'rniga ikki yield yozildi: soat va yarim soat. take(3) uchinchi bo'sh vaqtda zanjirni to'xtatdi — generator atigi olti satr yasadi. Haqiqiy ilovada yuqori chegara ham qo'ying: yarimSoatlar(10).take(24) — 10:00 dan 22:00 gacha bo'lgan 24 ta oraliq. Aks holda hamma vaqt band bo'lsa, filter bo'sh vaqtni abadiy qidiradi («Cheksiz ketma-ketliklar bilan» bo'limidagi ogohlantirish).

3-mashq (qiyin): O'z Iterator.concat ingiz

Node 24 da Iterator.concat yo'q. ula(...iterablelar) funksiyasini yozing: u bir nechta iterable'ni ketma-ket ulab, helper'lari bor iterator qaytarsin. Ya'ni ula(a, b).map(...) ishlashi kerak. Ishora: yield* va generator — generatorlar helper'larni meros oladi.

js
const issiq = ["osh", "manti"];
const ichimlik = new Set(["ko'k choy"]);
console.log(ula(issiq, ichimlik).map((t) => t.length).toArray());
// [ 3, 5, 9 ]
Yechim
js
function* ula(...iterablelar) {
  for (const iterable of iterablelar) {
    yield* iterable;
  }
}

const issiq = ["osh", "manti"];
const ichimlik = new Set(["ko'k choy"]);
const zanjir = ula(issiq, ichimlik).map((t) => t.length);
console.log(zanjir.toArray()); // [ 3, 5, 9 ]
console.log(ula("ab", [1]).toArray()); // [ 'a', 'b', 1 ]

...iterablelar — rest parametr (Spread va rest): istalgan sondagi argumentni massivga yig'adi. Har biri uchun yield* ishni o'sha iterable'ga topshiradi (Generatorlar chuqur). ula generator funksiya bo'lgani uchun qaytgan obyekt Iterator.prototype dan meros oladi — map va toArray o'z-o'zidan bor. Iterator.concat ishlaydigan muhitda ula ni u bilan almashtirish mumkin.

4-mashq: Vazifalar qadami — helper'lar royxat ustida (mashqlar repo)

Generatorlar chuqur darsidan keyin VazifalarRoyxati iteratori — generator, demak unda iterator helpers bor. Bu qadam mashqlar reposida: kurs/mashqlar/10/54-iterator-helpers/royxat.js.

  1. Royxatning qisqa nusxasini ko'chiring (#vazifalar, static dan, statistika() — Object.groupBy bilan, *[Symbol.iterator]()).
  2. Iterator helpers bilan, royxatni massivga aylantirmasdan hisoblang: faol vazifalar soni, birinchi faol vazifa matni, barcha matnlar "; " bilan.
  3. statistika().qoldi bilan solishtiring.
  4. Bitta-ikki gap: vazifalar.js dagi metodlarni iterator helpers'ga o'tkazish kerakmi?
Yechim
js
function guruhNomi(vazifa) {
  return vazifa.bajarildi ? "bajarilgan" : "faol";
}

class VazifalarRoyxati {
  #vazifalar = [];

  static dan(malumotlar) {
    const yangi = new VazifalarRoyxati();
    yangi.#vazifalar = malumotlar.map((m) => ({ ...m }));
    return yangi;
  }

  statistika() {
    const guruhlar = Object.groupBy(this.#vazifalar, guruhNomi);
    return {
      qoldi: guruhlar.faol?.length ?? 0,
      bajarildi: guruhlar.bajarilgan?.length ?? 0,
    };
  }

  *[Symbol.iterator]() {
    yield* this.#vazifalar;
  }
}

const royxat = VazifalarRoyxati.dan([
  { id: 1, matn: "Non olish", bajarildi: false },
  { id: 2, matn: "DOM darsini takrorlash", bajarildi: true },
  { id: 3, matn: "Onamga qo'ng'iroq qilish", bajarildi: false },
]);

const faollar = Iterator.from(royxat)
  .filter((v) => !v.bajarildi)
  .reduce((soni) => soni + 1, 0);
const birinchiFaol = Iterator.from(royxat).find((v) => !v.bajarildi);
const matnlar = Iterator.from(royxat)
  .map((v) => v.matn)
  .toArray()
  .join("; ");

console.log(faollar, royxat.statistika().qoldi); // 2 2
console.log(birinchiFaol.matn); // Non olish
console.log(matnlar);

Konsolda:

text
2 2
Non olish
Non olish; DOM darsini takrorlash; Onamga qo'ng'iroq qilish

Iterator.from(royxat) royxatning generatorini oldi. Har hisob uchun yangi Iterator.from chaqirildi — iterator bir martalik. join — massiv metodi, shuning uchun avval toArray(). Iteratorlar uchun join ham tayyorlanmoqda (Chrome 153, Firefox 154 da bor), lekin u hali Baseline emas va Node 24 da yo'q.

Javob: o'tkazmaymiz. vazifalar dagi ro'yxat kichik va hamma element kerak — massiv metodlari bu yerda oddiyroq va biroz tezroq («O'lchaymiz» bo'limidagi grafik). Ilova ommaviy saytda (GitHub Pages) ishlaydi, iterator helpers esa hali "widely available" emas — Safari 18.4 dan eski telefonlarda ilova ishlamay qolardi. Royxatning iterable bo'lgani foydali — kerak bo'lsa helper'lar tayyor. Lekin "yangi" degani "yaxshiroq" degani emas.

Commit (mashqlar repo): 10/54: royxat ustida iterator helpers bilan hisob.

12. Real ishda

  • Node.js skriptlari va serverlar. Katta log fayllarni, baza natijalarini qatorma-qator qayta ishlashda filter().map().take() — oraliq massivsiz, xotirani tejab. Node 22+ da tayyor.
  • Ma'lumot oqimlari. Sahifalab keladigan API natijalari, fayl qatorlari — generator + helper'lar. Asinxron variantlari (for await...of, async generator) Asinxron iteratsiya darsida.
  • Kutubxonalar o'rnini egallash. Ilgari dangasa zanjir uchun Lodash'ning _.chain yoki iter-tools, IxJS kabi kutubxonalar kerak edi. Endi asosiy qismi tilning o'zida — bog'liqlik kamayadi.
  • Intervyu. "Iterator helpers nima va massiv metodlaridan farqi?", "Dangasa hisob qachon foydali, qachon zararli?" — 2025-yildan beri yangi, lekin tez-tez beriladigan savollar. Grafikdagi ikki xulosa — tayyor javob.

Xulosa

  • Har bir o'rnatilgan iterator (massiv values(), Map/Set, generator) ES2025 dan map, filter, take, drop, flatMap, reduce, toArray, some, every, find, forEach ga ega.
  • O'zgartiruvchilar yangi iterator qaytaradi va hech narsa hisoblamaydi; yakunlovchilar zanjirni ishga tushiradi.
  • Zanjir elementma-element ishlaydi: "birinchi N ta" da yuzlab marta tez, "hammasi" da massivdan biroz sekin.
  • Callback imzosi — (qiymat, hisoblagich), uchinchi argument yo'q; flatMap satr qaytarishni qabul qilmaydi.
  • Iterator.from() — qo'lda yozilgan iterator yoki iterable'ga helper'lar beradi.
  • Baseline 2025 (Chrome 122, Firefox 131, Safari 18.4), hali widely available emas; Node 22+ da bor. Iterator.concat — Node 24 da yo'q.

Keyingi dars: try / catch / finally — xatolarni ushlash: generator darslarida ko'rgan try va catch ni to'liq o'rganamiz.

Manbalar

  • MDN: "Iterator", "Iterator.prototype.map()", "Iterator.from()", "Iterator.concat()" — developer.mozilla.org
  • TC39 taklifi: "Iterator Helpers" (ES2025) — github.com/tc39/proposal-iterator-helpers
  • web-features 3.40 (npm paketi): iterator-methods — Baseline 2025-03-31; iterator-concat — Baseline 2026-03-24
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript iterator helpers (ES2025): map, filter, take dangasa ishlaydi — IlmHamroh