Diziler Kendi Araç Kutusuyla Gelir
JavaScript dizileri, hazır metotlarla dolu zengin bir araç kutusuna sahiptir. for döngüsüyle yazacağınız şeylerin çoğu — değerleri dönüştürmek, bazılarını seçip ayıklamak, toplamını almak — tek satırda iş gören, okunması çok daha kolay ve birbiriyle güzelce zincirlenebilen bir metoda karşılık gelir.
Başlangıç seti üç metottan oluşur: map, filter ve reduce. Bu üçünü ve birkaç yakın akrabasını öğrendiğinizde, döngülerle şişmiş kodunuz bir bakışta anlaşılır hale gelir.
Her metot bir callback alıyor ve bir şey döndürüyor. Hiçbiri nums dizisini değiştirmedi — bunu erkenden kafaya kazımakta fayda var.
map: Her Elemanı Dönüştürmek
map metodu, verdiğin fonksiyonu dizinin her elemanı için çalıştırır ve dönen değerleri aynı uzunlukta yeni bir diziye toplar. Yani "her girdiye bir çıktı" istediğinde map kullanımı tam sana göre.
Callback fonksiyonu, ihtiyacın olursa ikinci argüman olarak index'i de alır: arr.map((item, i) => ...). Kullanmayacaksan görmezden gel.
Sık yapılan bir hata: dönen diziye ihtiyacın olmadığı halde refleks olarak map kullanmak. Amacın sadece her elemanı yazdırmak ya da veritabanına eklemekse, oraya forEach veya klasik bir döngü yakışır.
filter: Koşulu Sağlayanları Süz
filter metodu, her eleman için bir predicate — yani true ya da false döndüren bir fonksiyon — çalıştırır ve truthy değer dönenleri tutar. Yeni dizi ya aynı uzunlukta olur ya da daha kısa.
map ve filter birbirine doğal bir şekilde zincirlenir. Zinciri soldan sağa bir pipeline gibi okuyabilirsin:
Önce filter, sonra map uygula — böylece map yalnızca elemeyi geçenler üzerinde çalışır.
reduce: Diziyi Tek Bir Değere İndirgemek
reduce, bu üçlünün en esnek olanı. Ona bir indirgeyici fonksiyon (accumulator, item) => newAccumulator ve bir başlangıç değeri veriyorsun. Diziyi baştan sona dolaşıyor, her elemanı o ana kadarki akümülatörle birlikte fonksiyona veriyor ve sonunda akümülatörün ulaştığı değeri döndürüyor.
Sonucun illa bir sayı olması gerekmiyor. Bir nesne, başka bir dizi, bir string — ne istersen onu inşa edebilirsin:
İlk değeri (ikinci argümanı) her zaman ver. Vermezsen reduce, dizinin ilk elemanını başlangıç akümülatörü olarak kullanır; bu da boş dizilerde patlar ve çoğu zaman zaten istediğin davranışı vermez.
reduce güçlü bir metot ama işin mantığı karışınca okunması zorlaşabilir. Reducer fonksiyonun birkaç satırı geçiyorsa, sade bir for...of döngüsü genelde çok daha anlaşılır olur.
forEach: Yan Etkiler İçin, Dönüş Değeri Yok
forEach'i, geriye dizi döndürmeyen bir map gibi düşünebilirsin. Her eleman için bir şey yapmak istediğinde işe yarar — konsola yazdırmak, API çağırmak, DOM'u güncellemek gibi. Yeni bir koleksiyona ihtiyacın yoksa tam aradığın metot bu.
Bilmeniz gereken iki şey var:
forEachgeriyeundefineddöner. Yani sonrasına.map()zincirleyemezsiniz.forEachiçindenbreakile erken çıkış yapamazsınız. Erken çıkmanız gerekiyorsafor...ofya dasome/everykullanın.
Kendinizi arr.forEach(x => results.push(transform(x))) yazarken bulduğunuz an, aslında yapmak istediğiniz şey map'tir.
find ve findIndex: Tek bir eleman yeter
find, koşulu sağlayan ilk elemanı döner; hiçbir eleman eşleşmezse undefined gelir. findIndex ise bu elemanın indeksini (bulamazsa -1) döner.
find, ilk eşleşmede durur. filter(...)[0] yazmaktan kaçının — bütün diziyi tarayıp geri kalanını boşuna çöpe atar.
some ve every: Diziye Evet/Hayır Sormak
some, dizide testten geçen en az bir eleman varsa true döner. every ise yalnızca tüm elemanlar testi geçerse true döner.
Her ikisi de kısa devre yapar — some ilk true değerinde durur, every ise ilk false değerinde. "Herhangi biri…" / "Hepsi…" sorularını cevaplamak için tam da aradığınız araçlar bunlar.
slice ve splice farkı: Kopyalamak mı, Kesmek mi?
İsimleri benzese de yaptıkları iş tamamen farklı.
slice(start, end) dizinin bir bölümünün yüzeysel (shallow) kopyasını döndürür. Orijinal diziye dokunmaz. end parametresi dahil değildir; yazmazsanız dizinin sonuna kadar gider.
splice(start, deleteCount, ...items) diziyi yerinde değiştirir. start indeksinden itibaren deleteCount kadar elemanı siler, istersen yerine yeni elemanlar ekler ve silinen elemanları geriye döndürür.
Hatırlatma: slice güvenlidir (kopya alır), splice ise diziyi yerinde ameliyat eder.
Diziyi Değiştiren ve Değiştirmeyen Metotlar
Bu ayrım gerçekten önemli. Paylaşılan bir diziyi farkında olmadan değiştiren kod, izini sürmesi en can sıkıcı hatalardan biri olabiliyor.
Diziyi değiştirenler (orijinali değiştirir, genelde başka bir şey döndürürler):
push,pop,shift,unshiftsplice,sort,reversefill,copyWithin
Diziyi değiştirmeyenler (yeni bir dizi veya değer döner, orijinale dokunmaz):
map,filter,slice,concatflat,flatMapfind,findIndex,some,every,includes,indexOfreduce,reduceRight
Dikkat edilmesi gereken iki tane var: sort ve reverse. Masum görünürler ama sessiz sedasız diziyi değiştirirler. Sıralanmış bir kopyaya ihtiyacın varsa önce slice ile kopyala:
Modern JS'in bu metotların mutasyona yol açmayan ikizleri de var: toSorted, toReversed, toSpliced ve with. Bunlar yeni bir dizi döndürür, orijinaline dokunmaz. Güncel tüm runtime'larda destekleniyor — elinizin altındaysa tercih edin.
flat ve flatMap
flat metodu, iç içe geçmiş dizileri tek seviye düzleştirir (derinlik parametresi verirseniz daha fazlasını da yapabilir). flatMap ise aslında map işleminin ardından tek seviyelik bir flat uygulanmış hâlidir — her elemanın sıfır veya daha fazla çıktıya dönüşebildiği durumlarda oldukça kullanışlıdır.
flatMap, bir girdiden birden fazla çıktı üretirken araya flat() sokmadan işi tertemiz halleden metottur — yani öğeleri "genişletmenin" en şık yolu.
Hepsini Bir Araya Getirelim
Gerçek hayattan küçük bir örnek: Elimizde bir sipariş listesi var ve tamamlanmış, 50 doların üzerindeki siparişlerin toplam cirosunu hesaplamak istiyoruz:
Üç metot, tek bir işlem zinciri, hiçbir döngü takibi yok. Her adım ne yaptığını kendisi anlatıyor. İki filter çağrısını tek bir ifadede birleştirebilirsin elbette, ama ayrı bırakmak da gayet okunaklı — hatta hata ayıklarken bazen daha da rahat oluyor.
Sırada: Map ve Set
Diziler, sıralı veri dizilerini yönetmekte iyidir; ama anahtara göre hızlı erişim ya da benzersiz değerlerden oluşan bir koleksiyon gerektiğinde hantal kalırlar. JavaScript tam da bu iki iş için yerleşik iki veri yapısı sunuyor: Map ve Set. Sonraki sayfanın konusu işte bunlar.
Sıkça Sorulan Sorular
JavaScript'te map, filter ve reduce arasındaki fark nedir?
map her elemanı dönüştürür ve aynı uzunlukta yeni bir dizi döndürür. filter testten geçen elemanları tutar, genelde daha kısa yeni bir dizi döndürür. reduce ise dizinin üzerinden geçer ve onu tek bir değere indirger — bir toplam, bir nesne, başka bir dizi, ne kurarsan.
forEach ile map arasındaki fark ne?
forEach her eleman için fonksiyonu çalıştırır ve undefined döndürür — yani yan etkiler için kullanılır. map ise her eleman için fonksiyonu çalıştırır ve sonuçlardan oluşan yeni bir dizi döndürür. Dönüştürülmüş bir diziye ihtiyacın varsa map kullan. Sadece her elemanla bir iş yapacaksan ve sonuç umurunda değilse forEach (ya da for...of) yeterli.
Hangi dizi metotları orijinal diziyi değiştirir?
Diziyi değiştiren metotlar şunlar: push, pop, shift, unshift, splice, sort, reverse, fill ve copyWithin. Geri kalan herkes — map, filter, slice, concat, flat, flatMap, find, some, every, reduce — orijinal diziye dokunmaz, yeni bir değer döndürür.
slice mı splice mı kullanmalıyım?
slice(start, end) dizinin bir bölümünün yüzeysel bir kopyasını döndürür, orijinale dokunmaz. splice(start, deleteCount, ...items) ise diziyi yerinde değiştirir — eleman silip ekler ve silinenleri geri döndürür. Aklında kalsın: slice güvenlidir, splice ameliyat yapar.