İki döngü, iki farklı iş
JavaScript'te neredeyse aynı görünen ama bambaşka işler yapan iki döngü var. for...of bir iterable'ın değerleri üzerinde gezinir. for...in ise bir nesnenin anahtarları üzerinde gezinir. Tek harf fark, ama davranış tamamen farklı.
Tüm hikâyeyi tek bir örnekte görelim:
İlk döngü apple, banana, cherry yazdırır — yani değerleri. İkincisi ise 0, 1, 2 yazdırır — yani anahtarları, hem de string olarak. Yanlışını seçersen, dizinin neden sayılarla dolu olduğunu anlamaya çalışarak on dakika harcarsın.
for...of: Iterable olan her şeyden değer almak
for...of, günlük hayatta en sık uzanacağın döngüdür. JavaScript'in iterable saydığı her şeyde çalışır: diziler, stringler, Map, Set, NodeList, generator'lar ve dahası.
İndeksle uğraşmak yok, scores[i] yazmana gerek yok. Her değeri istersin, her değeri alırsın. String'ler de iterable olduğu için for...of onları karakter karakter gezer:
Bu yöntem, çoğu Unicode karakteriyle de sorunsuz çalışıyor; string'e sayısal index'le erişmeye kıyasla küçük ama gerçek bir avantaj.
for...of ile Index Alma
for...of döngüsünün sana doğrudan vermediği tek şey elemanın sırası. Index'e ihtiyacın olduğunda entries() ile birlikte kullanman yeterli:
names.entries() sana [index, value] şeklinde çiftler döndürür; baştaki destructuring de bunları iki ayrı değişkene ayırır. Sırf i'ye ihtiyacın var diye klasik for (let i = 0; ...) yazmaktan genelde çok daha temiz bir yoldur.
for...in: Nesnenin Anahtarları Üzerinde Döngü
for...in, düz nesneler için tasarlanmıştır. Nesnenin enumerable string anahtarları üzerinde döner:
Dikkat: burada değeri değil, anahtarı (key) alırsın. Değere erişmek için user[key] şeklinde tekrar nesneye girmen gerekir. Ayrıca her anahtar bir string'dir — sayı gibi görünse bile.
for...in prototip zincirini de dolaştığı için miras alınan özellikleri de önüne getirebilir. Kendi yazdığın literal nesnelerde bu pek sorun olmaz; ama bir sınıfın örnekleri ya da bir kütüphaneden gelen nesneler üzerinde döngü kurarken temkinli olmakta fayda var:
Object.hasOwn(user, key) kalıtım yoluyla gelen özellikleri es geçer. Modern kodda çoğu geliştirici for...in kullanmaktan tamamen kaçınıyor; onun yerine Object.keys, Object.values veya Object.entries tercih ediliyor — ki bu da bizi bir sonraki bölüme getiriyor.
JavaScript'te Nesne Üzerinde Döngü Kurmanın Modern Yolu
for...in yerine for...of döngüsünü Object.* yardımcılarından biriyle birleştirmek çok daha yaygın bir yaklaşım. İhtiyacına göre bu üçünden birini seçiyorsun:
Object.entries burada gerçekten çok işe yarıyor — [key, value] çiftini destructuring ile açtığınızda kod neredeyse düz cümle gibi okunuyor. Üstelik bu metotlar yalnızca nesnenin kendi enumerable özelliklerini döndürdüğü için, prototip zincirinden sızan gereksiz şeylerle uğraşmak zorunda kalmazsınız.
Dizilerde for...in Kullanmayın
Teknik olarak çalışıyor, evet — ama insanları tökezleten klasik bir tuzak:
0, 1, 2 derken tag de geliyor. Birinin diziye eklediği herhangi bir property — ya da polyfill üzerinden Array.prototype'a iliştirilen her şey — karşına çıkar. Üstüne anahtarlar string olduğu için key + 1 toplama yapmaz, stringleri birleştirir. Bir de iterasyon sırasının her edge case'te dizi sırasıyla eşleşeceğinin garantisi yok.
Pratik kural:
- Dizinin değerleri mi lazım?
for...of arr. - Hem index hem değer mi lazım?
for...of arr.entries(). - Sadece index ile sayaç mı tutacaksın? Klasik
for (let i = 0; i < arr.length; i++). - Nesnenin anahtarları ya da entry'leri mi?
Object.keys(obj)/Object.entries(obj)ile birliktefor...of.
Kısacası: for...in oldukça niş bir araç. for...of ile Object yardımcılarını birleştirince ihtiyacın olan her şeyi karşılıyorsun.
break ve continue Her İkisinde de Çalışır
Her iki döngü de bildiğimiz erken çıkış araçlarını destekler:
continue bir sonraki iterasyona atlar; break ise döngüden tamamen çıkar. Zaten for...of döngüsünü .forEach() yerine tercih etmenin asıl sebebi de bu: forEach içindeki callback'ten break ile çıkamazsınız, ama for...of buna izin verir.
Yan yana karşılaştırma
Dört farklı döngü, dört farklı görev ama aslında tek bir zihinsel model: Iterable bir şeyden değerleri almak istiyorsan for...of kullan. Bir nesnenin özellikleriyle çalışacaksan Object.keys / Object.values / Object.entries üzerinden yine for...of ile ilerle. for...in'i ise sadece bir nesnenin (kalıtımla gelenler dahil) tüm enumerable string key'lerini gerçekten istediğin o ender durumlar için sakla.
Sırada: Truthy ve Falsy
JavaScript'teki her döngü ve her if, eninde sonunda aynı soruyu sorar: bu değer true sayılıyor mu? Ve bu sorunun cevabı her zaman göründüğü kadar net değildir — boş string, sıfır, null ve undefined, hepsi beklediğinden farklı davranabilir. Sırada truthy ve falsy değerler var.
Sıkça Sorulan Sorular
JavaScript'te for...of ile for...in arasındaki fark nedir?
for...of, dizi, string, Map, Set gibi iterable yapıların değerleri üzerinde döner. for...in ise bir nesnenin anahtarları (property isimleri) üzerinde döner. Örneğin ['a', 'b'] dizisinde for...of size 'a' ve 'b' değerlerini verir; for...in ise string olarak '0' ve '1' döndürür.
for...of'u nesne üzerinde kullanabilir miyim?
Doğrudan kullanamazsınız — sade nesneler iterable değildir. Önce Object.keys(obj), Object.values(obj) veya Object.entries(obj) ile bir dizi elde edip onu for...of ile dönmeniz gerekir. En yaygın kalıp şudur: for (const [key, value] of Object.entries(obj)).
for...in dizilerde neden tercih edilmez?
Teknik olarak çalışır ama for...in tüm enumerable property'leri dolaşır; buna kalıtımla gelenler ve birinin Array.prototype'a eklediği şeyler de dahildir. Üstelik anahtarları string olarak döndürür ve integer benzeri anahtarların sırası her durumda garanti değildir. Değerler için for...of, index'e ihtiyacınız varsa klasik for döngüsünü kullanın.