İçeriğe geç
academia.sh

Ders 12 / 21

Döngüler

Sayaçlı, koşullu ve koleksiyon döngüleri; `for...in` ile `for...of` ayrımı, döngü denetimi, etiketli çıkış ve nesneler üzerinde gezinme.

İçindekiler

Önceki ders tek bir ölçümü sınıflandırdı. Listenin tamamını işlemek için tekrar gerekir. Programlama Temelleri kursundaki Döngüler ve Döngü Denetimi derslerinde bu yapıların amacı ve döngü değişmezi kavramı kurulmuştu; burada JavaScript’in sunduğu biçimler ve aralarındaki — özellikle iki koleksiyon döngüsü arasındaki — fark ele alınıyor.

Dört döngü biçimi vardır ve seçim keyfi değildir: sayaçlı döngü dizin gerektiğinde, koşullu döngü tekrar sayısı önceden bilinmediğinde, koleksiyon döngüleri ise doğrudan elemanlar üzerinde çalışıldığında kullanılır.

Sayaçlı ve Koşullu Döngüler

Klasik for döngüsü üç bölümden oluşur: başlatma, koşul ve tur sonu işlemi. Değişken Bildirimleri dersinde gösterildiği gibi, sayaç let ile bildirilir ve her turda yeniden bağlanır.

const sicakliklar = [21.5, 19.75, 23, 18.25];

for (let i = 0; i < sicakliklar.length; i++) {
  console.log(i, sicakliklar[i]);
}
0 21.5
1 19.75
2 23
3 18.25

while döngüsü yalnızca koşul taşır; tekrar sayısı önceden bilinmediğinde kullanılır:

const sicakliklar = [21.5, 19.75, 23, 18.25];
let i = 0;
while (i < sicakliklar.length && sicakliklar[i] < 23) {
  i += 1;
}
console.log("ilk 23 ve ustu dizin:", i);
ilk 23 ve ustu dizin: 2

Koşuldaki sıra önemlidir. Sınır denetimi (i < sicakliklar.length) önce yazılmıştır; kısa devre değerlendirme sayesinde dizin aşıldığında ikinci karşılaştırma hiç yapılmaz. Ters sırada yazılsaydı, dizinin sonunda undefined < 23 karşılaştırması yapılırdı — bu ifade NaN üreten bir zorlamadan geçtiği için yanlış verir ve döngü yine biterdi, ama gerekçesi denetim değil rastlantı olurdu.

do...while biçimi gövdeyi en az bir kez çalıştırır; koşul tur sonunda sınanır:

let tur = 0;
do {
  tur += 1;
} while (tur < 3);
console.log("tur:", tur);
tur: 3

İki Koleksiyon Döngüsü

JavaScript’te birbirine benzeyen iki koleksiyon döngüsü vardır ve farklı şeyler verirler.

for...in, nesnenin sayılabilir özellik anahtarlarını verir. for...of, yinelenebilir bir değerin elemanlarını verir.

const sicakliklar = [21.5, 19.75, 23];

for (const dizin in sicakliklar) {
  console.log(typeof dizin, dizin);
}
for (const deger of sicakliklar) {
  console.log(typeof deger, deger);
}
string 0
string 1
string 2
number 21.5
number 19.75
number 23

İlk döngü dizinleri verdi ve dizinler dizgi tipindedir. Bunun nedeni nesne anahtarlarının dizgi olmasıdır; dizi de bir nesnedir ve dizinleri anahtar olarak taşır. Bu, for...in ile toplama yapan kodun neden metin birleştirdiğini açıklar — Tip Dönüşümü ve Zorlama dersindeki toplama kuralı devreye girer.

Fark, diziye bir özellik eklendiğinde daha da belirginleşir:

const sicakliklar = [21.5, 19.75, 23];
sicakliklar.kaynak = "A1";

for (const dizin in sicakliklar) {
  console.log("for...in:", dizin);
}
for (const deger of sicakliklar) {
  console.log("for...of:", deger);
}
console.log("length:", sicakliklar.length);
for...in: 0
for...in: 1
for...in: 2
for...in: kaynak
for...of: 21.5
for...of: 19.75
for...of: 23
length: 3

for...in dizi elemanı olmayan bir anahtarı da dolaştı; for...of yalnızca elemanları verdi. length değeri de değişmedi — eklenen özellik dizinin uzunluğuna sayılmaz.

Kursun kuralı buradan çıkar: diziler üzerinde for...of kullanılır. for...in yalnızca sıradan nesnelerin anahtarlarını dolaşmak için yazılır.

Dizin ile değeri birlikte isteyen durumda ayrı bir yöntem vardır:

const sicakliklar = [21.5, 19.75, 23];
for (const [dizin, deger] of sicakliklar.entries()) {
  console.log(dizin, deger);
}
0 21.5
1 19.75
2 23

Burada dizin sayı tipindedir. Köşeli ayraçlı yazım, çiftin iki bileşenini iki ada ayırır; bu yapıbozum (destructuring) biçimi Diziler ve Nesneler derslerinde ayrıntılı ele alınacak.

Nesneler Üzerinde Gezinme

Sıradan nesneler for...of ile dolaşılamaz:

const kayit = { istasyon: "A1", sicaklik: 21.5, nem: 48 };
try {
  for (const d of kayit) {
    console.log(d);
  }
} catch (hata) {
  console.log(hata.name + ": " + hata.message);
}
TypeError: kayit is not iterable

İleti kesindir: nesne yinelenebilir (iterable) değildir. Diziler, dizgiler ve bazı yerleşik koleksiyonlar yinelenebilirdir; sıradan nesneler değildir.

İki yol vardır:

const kayit = { istasyon: "A1", sicaklik: 21.5, nem: 48 };

for (const anahtar in kayit) {
  console.log(anahtar, kayit[anahtar]);
}
for (const [anahtar, deger] of Object.entries(kayit)) {
  console.log(anahtar, "=", deger);
}
istasyon A1
sicaklik 21.5
nem 48
istasyon = A1
sicaklik = 21.5
nem = 48

İkisi aynı sonucu verdi, ama kapsamları aynı değil. for...in kalıtılan özellikleri de dolaşır; Object.entries yalnızca nesnenin kendi özelliklerini verir. Kalıtım zinciri bir sonraki kursun konusudur; şimdilik ikinci biçimin daha dar ve daha öngörülebilir olduğunu bilmek yeterlidir. Kursta nesne gezinmesi Object.entries ile yazılacaktır.

Döngü Denetimi

break döngüyü bitirir, continue o turu atlar. İkisi de en içteki döngüye etki eder.

const kayitlar = [
  { istasyon: "A1", sicaklik: 21.5 },
  { istasyon: "A2", sicaklik: NaN },
  { istasyon: "B1", sicaklik: 23 },
  { istasyon: "B2", sicaklik: 18.25 },
];

let toplam = 0;
let sayac = 0;
for (const kayit of kayitlar) {
  if (Number.isNaN(kayit.sicaklik)) {
    continue;
  }
  toplam += kayit.sicaklik;
  sayac += 1;
}
console.log("gecerli okuma:", sayac, "ortalama:", toplam / sayac);

let ilkYuksek = null;
for (const kayit of kayitlar) {
  if (kayit.sicaklik > 22) {
    ilkYuksek = kayit.istasyon;
    break;
  }
}
console.log("ilk yuksek:", ilkYuksek);
gecerli okuma: 3 ortalama: 20.916666666666668
ilk yuksek: B1

Birinci döngü geçersiz kaydı atladı ve ortalamayı yalnızca geçerli okumalar üzerinden hesapladı — bölen olarak kayitlar.length yerine sayac kullanılması bu yüzden zorunludur. İkinci döngü aradığını bulunca durdu; kalan kayıtlara bakılmadı.

Ortalamanın basamakları, İlkel Tipler dersindeki kayan noktalı gösterimin sonucudur: 62.75 / 3 işleminin sonucu ikilik kesir olarak tam yazılamaz ve en yakın temsil edilebilir değere yuvarlanır.

İç içe döngüde dıştakini kesmek için etiket kullanılır:

const izgara = [[1, 2], [3, 4], [5, 6]];
disDongu: for (const satir of izgara) {
  for (const hucre of satir) {
    if (hucre === 4) {
      console.log("bulundu, iki dongu de kesiliyor");
      break disDongu;
    }
    console.log("bakilan:", hucre);
  }
}
bakilan: 1
bakilan: 2
bakilan: 3
bulundu, iki dongu de kesiliyor

Etiket, döngünün önüne konan bir addır; break ve continue bu adı alarak hangi döngüye etki edeceğini belirtir. Etiketsiz break yalnızca iç döngüyü keser ve dış döngü bir sonraki satıra geçerdi.

Etiketli çıkış seyrek gerekir. Aynı işi bir fonksiyon içine alıp return ile çıkmak çoğu zaman daha okunaklıdır; fonksiyon tanımı bir sonraki dersin konusudur.

Özet

  • Sayaçlı for dizin gerektiğinde, while tekrar sayısı bilinmediğinde, do...while gövdenin en az bir kez çalışması gerektiğinde kullanılır.
  • for...in özellik anahtarlarını verir ve anahtarlar dizgi tipindedir; for...of elemanları verir.
  • Dizilerde for...of kullanılır; for...in dizi olmayan özellikleri de dolaşır.
  • Sıradan nesneler yinelenebilir değildir; anahtar–değer gezinmesi Object.entries ile yazılır.
  • break ve continue en içteki döngüye etki eder; dıştakine ulaşmak için etiket kullanılır.

Sonraki Adım

Bu derste denetimler ve birikeçler döngü gövdesine gömüldü; aynı işi ikinci kez yapmak gerektiğinde kod kopyalanacaktı. Sonraki ders fonksiyonlara geçiyor ve JavaScript’e özgü bir ayrımla başlıyor: bir fonksiyonu bildirim olarak yazmakla bir ifade olarak yazmak arasındaki fark yalnızca sözdizimi değildir — adın ne zaman erişilebilir olduğunu da belirler.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat