IlmHamroh
JavaScript Full-stack/8-qism. JavaScript asoslari37/61-dars14 daqiqa
Mundarija (34)

JavaScript for...of va for...in: farqi va tuzoqlari

Qisqacha: for...of qiymatlar bo'ylab yuradi: satrning har bir belgisi, massivning har bir elementi. for...in esa obyektning kalitlari (xususiyat nomlari) bo'ylab yuradi. Qoida oddiy: satr va massiv uchun — for...of, obyekt uchun — for...in. Massivda for...in ishlatmang: u indekslarni satr sifatida beradi va begona kalitlarni ham qo'shib yuboradi.

Bu darsda

  • for...of bilan satr belgilari bo'ylab indekssiz yura olasiz.
  • for...in bilan obyekt kalitlari va qiymatlarini chiqara olasiz.
  • of va in farqini bir gap bilan tushuntira olasiz.
  • Massivda for...in nega xavfli ekanini ko'rsatib bera olasiz.
  • is not iterable xatosini tushunib, tuzata olasiz.

Oldin bilishingiz kerak: for sikli, break va continue, String asoslari: indeks, Ma'lumot turlari xaritasi.

1. Nega bu kerak?

for darsida satrning har bir harfini shunday olgan edik:

js
const ism = "Malika";

for (let i = 0; i < ism.length; i++) {
  console.log(ism[i]);
}

Bu ishlaydi. Lekin o'ylab ko'ring: bizga harflar kerak edi, xolos. Buning uchun esa uchta ish qildik — i ni 0 dan boshladik, i < ism.length shartini yozdik, ism[i] bilan harfni oldik. Har birida xato qilish mumkin: 1 dan boshlash, <= yozish, i ni unutish.

Hayotdan o'xshatish: ustoz sinfga daftar tarqatyapti. U "1-o'quvchi, 2-o'quvchi..." deb sanamaydi. Shunchaki "har bir o'quvchiga bittadan" beradi.

JavaScript'da ham shunday "har biri uchun" sikllari bor. Bu darsda ikkitasini o'rganamiz:

  • for...of — har bir qiymat uchun;
  • for...in — har bir kalit (nom) uchun.

Nomlari o'xshash, lekin vazifasi butunlay boshqa. Ularni adashtirish — JavaScript'dagi klassik xatolardan biri.

2. for...of — qiymatlar bo'ylab

2.1 Satrning har bir belgisi

js
const ism = "Malika";

for (const harf of ism) {
  console.log(harf);
}

Konsolda:

text
M
a
l
i
k
a

of — inglizchada "...ning". Sikl shunday o'qiladi: "ism ning har bir harfi uchun".

Hisoblagich yo'q, shart yo'q, ism[i] yo'q. Har aylanishda harf o'zgaruvchisiga navbatdagi belgi yoziladi. Belgilar tugaganda sikl o'zi to'xtaydi. Off-by-one xatosiga o'rin qolmaydi.

2.2 Nega bu yerda const ishlaydi?

for darsida ko'rgandik: for (const i = 0; ...; i++) xato beradi, chunki i++ o'zgarmasni o'zgartirishga urinadi.

for...of da esa hech narsa o'zgartirilmaydi. Har aylanishda yangi harf o'zgaruvchisi yaratiladi va unga bir marta qiymat beriladi. Shuning uchun const bemalol ishlaydi — va tavsiya etiladi. let ham ishlaydi, lekin sikl ichida harf ga yangi qiymat berish niyatingiz bo'lmasa, const yozing.

2.3 Misol: unli harflarni sanash

js
const xabar = "Assalomu alaykum";
let unlilar = 0;

for (const harf of xabar.toLowerCase()) {
  if ("aeiou".includes(harf)) {
    unlilar++;
  }
}

console.log(unlilar); // 7
  • xabar.toLowerCase() — hamma harflarni kichik harfga o'tkazadi (matnni o'zgartirish). Aks holda katta A sanalmay qolardi.
  • "aeiou".includes(harf) — "harf shu satr ichida bormi?" (matn ichida qidirish).

for...of dan keyin istalgan satr yoki qiymat qo'yish mumkin — o'zgaruvchi ham, xabar.toLowerCase() kabi ifoda ham.

2.4 break va continue ham ishlaydi

Oldingi darsdagi break va continue for...of da ham xuddi shunday ishlaydi. Login'da bo'sh joy bo'lmasligi kerak — birinchisini topgan zahoti to'xtaymiz:

js
const login = "jasur 2006";
let boshJoyBor = false;

for (const belgi of login) {
  if (belgi === " ") {
    boshJoyBor = true;
    break;
  }
}

console.log(boshJoyBor); // true

2.5 Emoji bilan to'g'ri ishlaydi

Unicode darsida ko'rgandik: ba'zi emojilar ichkarida ikkita "yarim belgi"dan iborat. Shuning uchun ularning length i 2 ga teng. Indeks bilan yursangiz, emoji ikkiga bo'linib ketadi. for...of esa emojini bitta butun belgi deb oladi:

js
const xabar = "Rahmat👍";
let sanoq = 0;

for (const belgi of xabar) {
  sanoq++;
}

console.log(xabar.length); // 8
console.log(sanoq); // 7

"Rahmat" — 6 harf, — 1 belgi. Haqiqiy belgilar 7 ta. length 8 deydi, for...of esa to'g'ri sanaydi. Telegram xabarlari, izohlar kabi foydalanuvchi matnlarida bu farq muhim.

2.6 Indeks ham kerak bo'lsa-chi?

for...of faqat qiymatni beradi. "Nechanchi harf?" degan savolga javob kerak bo'lsa, ikki yo'l bor:

  • oddiy for (let i = 0; ...) siklini ishlatish;
  • for...of ichida hisoblagichni o'zingiz yuritish: let i = 0; va har aylanishda i++.

Massivlarni o'rganganda yana bir qulay usulni ko'rasiz — massiv bo'ylab yurish darsida.

Tekshirib ko'ring: Quyidagi kod nechta qator chiqaradi va ular qanday?

js
for (const b of "Ok!") {
  console.log(b);
}
Javob

3 ta qator: O, k, !. for...of satrning har bir belgisini — harf bo'ladimi, belgi bo'ladimi — navbat bilan beradi. Undov belgisi ham belgi.

3. for...of nimalar bilan ishlaydi?

3.1 Birinchi tanishuv: massiv

Hozircha biz asosan satrlar bilan ishladik. Lekin for...of ning asosiy "ish joyi" — massiv (array). Uni kesish darsida split natijasi sifatida ko'rgansiz. Massiv — tartiblangan qiymatlar ro'yxati. U kvadrat qavsda, vergul bilan yoziladi. Xuddi bozorga olib boradigan xarid ro'yxati kabi:

js
const xaridlar = ["non", "sut", "tuxum"];

for (const narsa of xaridlar) {
  console.log(`Olish kerak: ${narsa}`);
}

Konsolda:

text
Olish kerak: non
Olish kerak: sut
Olish kerak: tuxum

Massivlarni massiv darsida batafsil o'rganamiz. Hozir faqat bitta narsani eslab qoling: ro'yxatning har bir elementi kerak bo'lsa — for...of.

3.2 Iterable — "aylanib chiqsa bo'ladigan"

for...of faqat iterable narsalar bilan ishlaydi. Iterable — ichidagi qiymatlarni birma-bir, tartib bilan bera oladigan narsa. Hozir bilganlaringizdan satr va massiv — iterable. Kursda keyinroq yana bir nechtasini (Map, Set kabi to'plamlarni) ko'rasiz.

Son esa iterable emas. 5 ning "ichidagi qiymatlar" degan narsa yo'q:

js
for (const x of 5) {
  console.log(x);
}
text
TypeError: 5 is not iterable

Tarjimasi: "5 — iterable emas", ya'ni "uni aylanib chiqib bo'lmaydi". 1 dan 5 gacha sanash kerak bo'lsa — oddiy for ishlating.

4. for...in — kalitlar bo'ylab

4.1 Birinchi tanishuv: obyekt

Ma'lumot turlari darsida obyekt haqida eshitgansiz, switch darsida esa uni "obyekt-lug'at" sifatida ishlatib ko'rdik. Obyekt — nomlangan qiymatlar to'plami. U jingalak qavsda, kalit: qiymat juftliklari bilan yoziladi. Xuddi choyxona menyusi kabi: taom nomi — va uning narxi.

js
const narxlar = { non: 4000, choy: 3000, somsa: 8000 };

Bu yerda non, choy, somsa — kalitlar (keys), 4000, 3000, 8000 — ularning qiymatlari. Obyektlarni obyekt darsida to'liq o'rganamiz. Hozir bizga shu tushuncha yetadi.

4.2 Kalitlarni chiqarish

for...in obyektning har bir kaliti bo'ylab yuradi:

js
const narxlar = { non: 4000, choy: 3000, somsa: 8000 };

for (const kalit in narxlar) {
  console.log(kalit);
}

Konsolda:

text
non
choy
somsa

E'tibor bering: narxlar emas, nomlar chiqdi. in — inglizchada "ichida". Sikl shunday o'qiladi: "narxlar ichidagi har bir kalit uchun".

4.3 Qiymatni olish: narxlar[kalit]

Kalit bilan uning qiymatini olish uchun kvadrat qavs ishlatiladi: narxlar[kalit] — switch darsidagi narxlar[ichimlik] kabi. Bu "narxlar dan shu kalitning qiymatini ber" degani. Satrdagi ism[i] ga o'xshaydi — faqat raqam o'rnida nom turadi.

js
const narxlar = { non: 4000, choy: 3000, somsa: 8000 };

for (const kalit in narxlar) {
  console.log(`${kalit} — ${narxlar[kalit]} so'm`);
}

Konsolda:

text
non — 4000 so'm
choy — 3000 so'm
somsa — 8000 so'm

Menyudagi hamma narsaning jami narxini ham hisoblash mumkin:

js
const narxlar = { non: 4000, choy: 3000, somsa: 8000 };
let jami = 0;

for (const kalit in narxlar) {
  jami += narxlar[kalit];
}

console.log(jami); // 15000

Obyektdan qiymat olishning boshqa usullarini (nuqta orqali, narxlar.non) obyekt darsida ko'rasiz. Hozir bitta tuzoqni bilib qo'ying — u "Ko'p uchraydigan xatolar" bo'limida.

4.4 Satrda for...in

for...in ni satrga ham qo'llash mumkin. Lekin u harflarni emas, indekslarni beradi:

js
for (const k in "Ali") {
  console.log(k);
}

Konsolda:

text
0
1
2

Harflar kerak edi — indekslar chiqdi. of va in ni adashtirsangiz, JavaScript xato bermaydi, shunchaki boshqa natija chiqaradi. Bunday xatoni topish qiyin.

Tekshirib ko'ring: const talaba = { ism: "Jasur", yosh: 19 }; uchun for (const k in talaba) { console.log(k); } nima chiqaradi?

Javob

ism va yosh — kalitlar. "Jasur" va 19 chiqishi uchun console.log(talaba[k]) yozish kerak. for...in doim nomlarni beradi, qiymatni kalit orqali o'zingiz olasiz.

5. Asosiy tuzoq: massivda for...in

Massiv ham obyektning bir turi — uning "kalitlari" indekslar (0, 1, 2...). Shuning uchun for...in massivda ham ishlaydi. Lekin ishlatmang. Mana uch sababi.

5.1 Indekslar — satr, son emas

js
const mevalar = ["olma", "nok"];

for (const i in mevalar) {
  console.log(i + 1);
}

Konsolda:

text
01
11

1 va 2 kutgandik, 01 va 11 chiqdi. Sabab: for...in kalitlarni doim satr sifatida beradi — "0", "1". + tuzog'ini eslang: satrga son qo'shilsa, ular yopishtiriladi: "0" + 1 → "01".

5.2 Begona kalitlar ham chiqadi

Massiv obyekt bo'lgani uchun unga nomli xususiyat ham qo'shish mumkin. Buni kamdan-kam qilishadi, lekin boshqalarning kodida uchraydi:

js
const mevalar = ["olma", "nok"];
mevalar.izoh = "bozordan olingan";

for (const k in mevalar) {
  console.log(k);
}

Konsolda:

text
0
1
izoh

for...in izoh ni ham ko'rsatdi — u meva emas-ku! for...of esa faqat elementlarni beradi:

js
const mevalar = ["olma", "nok"];
mevalar.izoh = "bozordan olingan";

for (const meva of mevalar) {
  console.log(meva);
}

Konsolda:

text
olma
nok

5.3 Meros kalitlar

Bu eng yashirin muammo. JavaScript'da har bir massiv umumiy "ajdod"dan imkoniyatlarni meros (inheritance) qilib oladi. Xuddi farzand ota-onasidan familiya olgani kabi. Buning qanday ishlashini prototip darsida ko'rasiz.

for...in o'z kalitlarini ham, meros kalitlarni ham ko'rsatadi. Tasavvur qiling: loyihangizdagi eski kutubxona hamma massivlarning ajdodiga bitta xususiyat qo'shib qo'ygan:

js
// ❌ Real kodda bunday qilmang — faqat tuzoqni ko'rsatish uchun
Array.prototype.eslatma = "salom";

const mevalar = ["olma", "nok"];

for (const k in mevalar) {
  console.log(k);
}

Konsolda:

text
0
1
eslatma

Siz mevalar ga hech narsa qo'shmadingiz. Lekin for...in baribir begona eslatma ni chiqardi. Eski saytlarda bunday xatolar ko'p bo'lgan. Eng yomoni — bu kalit sizning kodingizdan emas, boshqa joydan keladi, shuning uchun uni topish qiyin.

Maslahat: Nega massivning length i for...in da chiqmadi? Chunki for...in faqat sanaladigan (enumerable) kalitlarni ko'rsatadi. length ichki xususiyat va "sanalmaydigan" qilib belgilangan. Siz qo'shgan izoh va eslatma esa odatiy holda sanaladigan bo'ladi.

Obyektlarda ham shu muammo bor. Shuning uchun obyekt bilan ishlaganda ham ehtiyot choralari ko'riladi: Object.hasOwn bilan "bu kalit obyektning o'zinikimi?" deb tekshiriladi yoki Object.keys ishlatiladi. Bularni obyekt darsida va obyekt bo'ylab yurish darsida o'rganasiz.

5.4 Xulosa: qaysi siklni qachon ishlatish kerak

Sikl Nima beradi Qachon
for (let i ...) Hisoblagich (son) Indeks kerak, sanash, teskari yurish
for...of Qiymatlar Satr, massiv — har bir element uchun
for...in Kalitlar (satr) Obyekt — har bir kalit uchun

Oltin qoida: massivda for...in ishlatmang. Massiv uchun — for...of yoki oddiy for.

Eslab qolish uchun: for...in — indekslar va nomlar (kalitlar), for...of — qiymatlarning o'zi.

Tekshirib ko'ring: const ballar = [90, 75]; massivi uchun for (const x in ballar) { console.log(x); } nima chiqaradi? in o'rniga of bo'lsa-chi?

Javob

in bilan: 0 va 1 — indekslar, satr ko'rinishida. of bilan: 90 va 75 — qiymatlar. Ballar kerak bo'lgani uchun to'g'ri tanlov — for...of.

6. Ko'p uchraydigan xatolar

6.1 Obyektda for...of

js
const narxlar = { non: 4000, choy: 3000 };

for (const narx of narxlar) {
  console.log(narx);
}
text
TypeError: narxlar is not iterable

Tarjimasi: "narxlar — iterable emas". Oddiy obyektning qiymatlari tartiblangan ro'yxat emas, shuning uchun for...of uni aylana olmaydi. Tuzatish: obyekt uchun for...in ishlating. (Obyektni for...of ga "tayyorlab beradigan" Object.values va Object.entries ham bor — obyekt bo'ylab yurish darsida.)

6.2 narxlar.kalit — nuqta bilan olish

js
const narxlar = { non: 4000, choy: 3000 };

for (const kalit in narxlar) {
  console.log(narxlar.kalit);
}

Konsolda:

text
undefined
undefined

Xato yo'q, lekin qiymatlar ham yo'q. narxlar.kalit — "narxlar dan aynan kalit degan nomli xususiyatni ber" degani. Bunday nomli kalit yo'q, natija undefined. kalit o'zgaruvchisining ichidagi nomdan foydalanish uchun kvadrat qavs kerak: narxlar[kalit].

6.3 Massivda for...in va satr indekslar

Yuqorida ko'rdik: i + 1 → "01". Belgisi: kutilgan son o'rniga g'alati "yopishgan" raqamlar. Tuzatish: massivda for...of yoki oddiy for ishlating.

6.4 of o'rniga in (yoki aksincha)

Satrda for...in — harflar o'rniga 0, 1, 2. Massivda for...in — qiymatlar o'rniga indekslar. Xato chiqmaydi, faqat natija boshqacha. Sikl g'alati natija bersa, birinchi navbatda shu so'zni tekshiring.

6.5 Sikl o'zgaruvchisini o'zgartirish

js
for (const harf of "abc") {
  harf = harf.toUpperCase();
}
text
TypeError: Assignment to constant variable.

"O'zgarmas o'zgaruvchiga qiymat berish". harf — const. Natijani yangi o'zgaruvchiga yozing: const katta = harf.toUpperCase();. Yoki natijani sikldan tashqaridagi let o'zgaruvchiga yig'ing.

7. Mashqlar

1-mashq (oson): Harflarni sanash

"Samarqand" so'zida nechta "a" harfi borligini for...of bilan sanang. Natija: 3.

Yechim
js
const shahar = "Samarqand";
let soni = 0;

for (const harf of shahar) {
  if (harf === "a") {
    soni++;
  }
}

console.log(soni); // 3

Indeks, length, < — hech biri kerak bo'lmadi. Katta S ham sanalishi kerak bo'lsa (masalan, "s" harfini sanasangiz), shahar.toLowerCase() ni aylaning.

2-mashq (o'rta): Baholar jurnali

Talabaning baholari obyektda berilgan:

js
const baholar = { matematika: 5, fizika: 4, tarix: 3, ingliz: 4 };

for...in yordamida:

  1. Har bir fanni matematika: 5 ko'rinishida chiqaring.
  2. O'rtacha bahoni hisoblang va oxirida O'rtacha: 4 deb chiqaring.

Ishora: ikkita yig'uvchi o'zgaruvchi kerak — baholar yig'indisi va fanlar soni. O'rtacha = yig'indi / soni.

Yechim
js
const baholar = { matematika: 5, fizika: 4, tarix: 3, ingliz: 4 };
let yigindi = 0;
let soni = 0;

for (const fan in baholar) {
  console.log(`${fan}: ${baholar[fan]}`);
  yigindi += baholar[fan];
  soni++;
}

console.log(`O'rtacha: ${yigindi / soni}`);

Konsolda:

text
matematika: 5
fizika: 4
tarix: 3
ingliz: 4
O'rtacha: 4

Kalit nomi fan — ma'noli nom kodni o'qishni osonlashtiradi. Obyektda nechta kalit borligini oldindan bilmaymiz, shuning uchun soni ni sikl ichida sanadik.

3-mashq (qiyin): Palindrom

Palindrom — oldindan ham, orqadan ham bir xil o'qiladigan so'z: "kiyik", "qazaq", "non". for...of yordamida so'zni teskari aylantiring va palindrom ekanini tekshiring.

"kiyik" uchun natija: kiyik — palindrom. "olma" uchun: olma — palindrom emas (teskarisi amlo).

Ishora: let teskari = ""; dan boshlang. Har bir harfni satrning boshiga qo'shing: teskari = harf + teskari. Oxirida teskari === soz ni tekshiring (if / else yoki ternary).

Yechim
js
const soz = "kiyik";
let teskari = "";

for (const harf of soz) {
  teskari = harf + teskari;
}

if (teskari === soz) {
  console.log(`${soz} — palindrom`);
} else {
  console.log(`${soz} — palindrom emas`);
}

Konsolda:

text
kiyik — palindrom

"olma" uchun kuzatuv: "o" → "lo" → "mlo" → "amlo". Har yangi harf oldinga qo'yilgani uchun tartib teskari bo'ladi. "amlo" === "olma" — false, demak palindrom emas.

soz o'zgaruvchisini "olma" ga, keyin "non" ga o'zgartirib sinab ko'ring.

8. Real ishda

  • for...of — zamonaviy JavaScript'dagi eng ko'p ishlatiladigan sikllardan biri. Savatdagi mahsulotlar, chatdagi xabarlar, API'dan kelgan foydalanuvchilar ro'yxati — hammasi massiv va hammasi for...of bilan aylanadi.
  • for...in real kodda kamroq uchraydi. Obyektlar uchun ko'pincha Object.keys va Object.entries ishlatiladi — ular faqat obyektning o'z kalitlarini beradi.
  • Kod tekshiruvchi vositalar (masalan, ESLint — kod yozilishini tekshiradigan dastur, kursda alohida o'rganamiz) massivda for...in ni ko'pincha xato deb belgilaydi.
  • Meros kalitlar muammosi xavfsizlik bilan ham bog'liq: hujumchi umumiy "ajdod"ga kalit qo'shib, butun ilovani buzishga urinishi mumkin. Bu hujum prototype pollution deb ataladi — kursda alohida ko'ramiz.

Intervyularda "for...of va for...in farqi nima?" savoli juda ko'p beriladi. To'liq javob: "for...of iterable'ning qiymatlarini beradi, for...in esa obyektning sanaladigan kalitlarini — meros bo'lganlarini ham — satr sifatida beradi. Shuning uchun massivda for...in ishlatilmaydi."

Xulosa

  • for (const x of ...) — qiymatlar: satr belgilari, massiv elementlari. Indeks va off-by-one tashvishi yo'q.
  • for (const k in ...) — kalitlar: obyektning xususiyat nomlari. Qiymat — obyekt[k].
  • for...of faqat iterable bilan ishlaydi. Oddiy obyekt yoki son — TypeError: ... is not iterable.
  • for...in kalitlarni doim satr sifatida beradi va meros kalitlarni ham ko'rsatadi.
  • Massivda for...in ishlatmang — for...of yoki oddiy for tanlang.
  • for...of emojilarni bitta butun belgi deb sanaydi, indeks bilan yurish esa ularni bo'lib yuboradi.

Oldingi dars: break, continue va label'lar.

Keyingi dars: Funksiya e'lon qilish va chaqirish — kodni nomlab, xohlagancha qayta ishlatishni o'rganamiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!