Dizi Metotları Derinlemesine
Giriş — Veriyi Dönüştürmenin Gücü
Bir önceki derste dizilerin temellerini öğrendik — oluşturma, erişim, ekleme, silme. Ama dizilerin gerçek gücü, üzerlerinde yapabileceğiniz dönüşüm işlemlerinde yatar. Bir müşteri listesinden sadece aktif olanları çekmek, ürün fiyatlarının hepsine KDV eklemek, bir sınıfın not ortalamasını hesaplamak — bunlar hep veri dönüştürme işlemleridir.
JavaScript dizileri, bu dönüşümler için güçlü yerleşik metotlar sunar: map, filter, reduce, find, some, every, sort ve daha fazlası. Bu metotlar callback fonksiyonlar alır ve fonksiyonel programlama paradigmasının temelini oluşturur. Hepsini ayrı ayrı öğrendikten sonra, bunları zincirleme (chaining) ile birleştirerek karmaşık veri dönüşümlerini zarif bir şekilde yapabileceksiniz.
Analoji: Bu dizi metotlarını bir fabrikanın montaj hattı olarak düşünün. Hammadde (veri) hatta girer, her istasyonda (metot) bir işlemden geçer ve sonunda bitmiş ürün çıkar.
filtereleme istasyonudur (kötü parçaları ayıklar),mapdönüştürme istasyonudur (parçaları işler),reducebirleştirme istasyonudur (parçaları tek bir ürüne dönüştürür). Bu istasyonları istediğiniz sırayla birbirine bağlarsınız.
map() — Her Elemanı Dönüştür
map(), dizideki her elemanı bir fonksiyondan geçirir ve sonuçlardan yeni bir dizi oluşturur. Orijinal dizi değişmez.
// Temel kullanım — her sayının karesini al
const sayilar = [1, 2, 3, 4, 5];
const kareler = sayilar.map(sayi => sayi ** 2);
console.log(kareler); // [1, 4, 9, 16, 25]
console.log(sayilar); // [1, 2, 3, 4, 5] — orijinal değişmedi!
// Fiyatlara KDV ekleme
const fiyatlar = [100, 250, 50, 175];
const kdvliFiyatlar = fiyatlar.map(fiyat => +(fiyat * 1.18).toFixed(2));
console.log(kdvliFiyatlar); // [118, 295, 59, 206.5]
// Nesne dizisinde dönüşüm
const kullanicilar = [
{ isim: "Ali", yas: 25 },
{ isim: "Ayşe", yas: 30 },
{ isim: "Mehmet", yas: 28 }
];
// Sadece isimleri çek
const isimler = kullanicilar.map(k => k.isim);
console.log(isimler); // ["Ali", "Ayşe", "Mehmet"]
// Yeni alan ekle
const zenginlestirilmis = kullanicilar.map(k => ({
...k,
yetiskin: k.yas >= 18,
dogumYili: new Date().getFullYear() - k.yas
}));
console.log(zenginlestirilmis);
// [
// { isim: "Ali", yas: 25, yetiskin: true, dogumYili: 2000 },
// ...
// ]map() callback'inin parametreleri:
const harfler = ["a", "b", "c"];
harfler.map((eleman, index, tamDizi) => {
console.log(`eleman: ${eleman}, index: ${index}, dizi: [${tamDizi}]`);
return eleman.toUpperCase();
});
// eleman: a, index: 0, dizi: [a,b,c]
// eleman: b, index: 1, dizi: [a,b,c]
// eleman: c, index: 2, dizi: [a,b,c]⚠️ Dikkat: map() her zaman orijinal diziyle aynı uzunlukta yeni bir dizi döndürür. Elemanları filtrelemeniz gerekiyorsa map yerine filter kullanın. map içinde undefined döndürmek yaygın bir hatadır:
// ❌ map ile filtreleme yapmaya çalışmak — YANLIŞ
const sonuc = [1, 2, 3, 4, 5].map(n => {
if (n > 3) return n;
// else: undefined döner
});
console.log(sonuc); // [undefined, undefined, undefined, 4, 5] — istenmeyen!
// ✅ Önce filter, sonra map
const dogruSonuc = [1, 2, 3, 4, 5].filter(n => n > 3).map(n => n * 2);
console.log(dogruSonuc); // [8, 10]filter() — Koşula Göre Eleme
filter(), callback fonksiyonun true döndürdüğü elemanlardan yeni bir dizi oluşturur:
// Çift sayıları filtrele
const sayilar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const ciftler = sayilar.filter(n => n % 2 === 0);
console.log(ciftler); // [2, 4, 6, 8, 10]
// Aktif kullanıcıları filtrele
const kullanicilar = [
{ isim: "Ali", aktif: true, yas: 25 },
{ isim: "Ayşe", aktif: false, yas: 30 },
{ isim: "Mehmet", aktif: true, yas: 17 },
{ isim: "Fatma", aktif: true, yas: 22 },
{ isim: "Can", aktif: false, yas: 28 }
];
// Aktif VE yetişkin kullanıcılar
const aktifYetiskinler = kullanicilar.filter(k => k.aktif && k.yas >= 18);
console.log(aktifYetiskinler);
// [{ isim: "Ali"... }, { isim: "Fatma"... }]
// Arama fonksiyonu
function ara(dizi, sorgu) {
const kucukSorgu = sorgu.toLowerCase();
return dizi.filter(k =>
k.isim.toLowerCase().includes(kucukSorgu)
);
}
console.log(ara(kullanicilar, "me"));
// [{ isim: "Mehmet"... }]
// Boş/falsy değerleri temizleme
const karisik = [0, "Ali", "", null, "Ayşe", undefined, false, "Mehmet"];
const temiz = karisik.filter(Boolean); // Boolean fonksiyonu truthy/falsy filtreler
console.log(temiz); // ["Ali", "Ayşe", "Mehmet"]
// Tekrar eden elemanları kaldırma
const tekrarli = [1, 2, 2, 3, 3, 3, 4, 4, 5];
const benzersiz = tekrarli.filter((eleman, index, dizi) =>
dizi.indexOf(eleman) === index
);
console.log(benzersiz); // [1, 2, 3, 4, 5]
// Not: Set ile daha kısa: [...new Set(tekrarli)]reduce() — Tek Değere İndirgeme
reduce(), dizi elemanlarını tek bir değere birleştirir. En güçlü ama en zor anlaşılan dizi metotudur:
// Temel toplama
const sayilar = [10, 20, 30, 40];
const toplam = sayilar.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0); // 0: başlangıç değeri
console.log(toplam); // 100
// Adım adım:
// acc=0, cur=10 → 0+10=10
// acc=10, cur=20 → 10+20=30
// acc=30, cur=30 → 30+30=60
// acc=60, cur=40 → 60+40=100`reduce` parametreleri: `(callback, başlangıçDeğeri)`
Callback: (accumulator, currentValue, index, array) => yeniAccumulator
// Kısa yazım
const toplam2 = [1, 2, 3, 4, 5].reduce((acc, n) => acc + n, 0); // 15
// Maksimum değer bulma
const max = [5, 3, 8, 1, 9, 2].reduce((acc, n) => n > acc ? n : acc, -Infinity);
console.log(max); // 9
// Nesne dizisinde toplama
const sepet = [
{ urun: "Laptop", fiyat: 15000, adet: 1 },
{ urun: "Mouse", fiyat: 250, adet: 2 },
{ urun: "Klavye", fiyat: 500, adet: 1 }
];
const toplamFiyat = sepet.reduce((acc, item) => acc + item.fiyat * item.adet, 0);
console.log(`Toplam: ${toplamFiyat} TL`); // "Toplam: 16000 TL"reduce ile İleri Kullanımlar
// Gruplama — en yaygın reduce kullanımlarından biri
const ogrenciler = [
{ isim: "Ali", sinif: "10-A" },
{ isim: "Ayşe", sinif: "10-B" },
{ isim: "Mehmet", sinif: "10-A" },
{ isim: "Fatma", sinif: "10-B" },
{ isim: "Can", sinif: "10-A" }
];
const siniflaraGore = ogrenciler.reduce((acc, ogr) => {
const sinif = ogr.sinif;
if (!acc[sinif]) {
acc[sinif] = []; // Yeni grup oluştur
}
acc[sinif].push(ogr.isim);
return acc;
}, {});
console.log(siniflaraGore);
// { "10-A": ["Ali", "Mehmet", "Can"], "10-B": ["Ayşe", "Fatma"] }
// Modern alternatif: Object.groupBy() (ES2024)
// const grouped = Object.groupBy(ogrenciler, ogr => ogr.sinif);
// Frekans sayma
const kelimeler = ["elma", "armut", "elma", "portakal", "armut", "elma"];
const frekans = kelimeler.reduce((acc, kelime) => {
acc[kelime] = (acc[kelime] || 0) + 1;
return acc;
}, {});
console.log(frekans); // { elma: 3, armut: 2, portakal: 1 }
// Pipeline — reduce ile fonksiyon zinciri
const islemler = [
n => n * 2,
n => n + 10,
n => n / 3
];
const sonuc = islemler.reduce((deger, fn) => fn(deger), 15);
console.log(sonuc); // ((15 * 2) + 10) / 3 = 13.333...⚠️ Dikkat: reduce'da başlangıç değerini her zaman belirtin. Belirtmezseniz, dizinin ilk elemanı başlangıç değeri olur — boş dizide hata fırlatır:
// ❌ Boş dizide başlangıç değeri olmadan hata
// [].reduce((a, b) => a + b); // TypeError!
// ✅ Başlangıç değeri ile güvenli
[].reduce((a, b) => a + b, 0); // 0 — hata yokfind() ve findIndex()
const urunler = [
{ id: 1, isim: "Laptop", fiyat: 15000 },
{ id: 2, isim: "Telefon", fiyat: 8000 },
{ id: 3, isim: "Tablet", fiyat: 5000 },
{ id: 4, isim: "Kulaklık", fiyat: 1500 }
];
// find() — koşula uyan İLK elemanı döndürür (veya undefined)
const ucuzUrun = urunler.find(u => u.fiyat < 3000);
console.log(ucuzUrun); // { id: 4, isim: "Kulaklık", fiyat: 1500 }
// findIndex() — koşula uyan ilk elemanın INDEX'ini döndürür (veya -1)
const tabletIndex = urunler.findIndex(u => u.isim === "Tablet");
console.log(tabletIndex); // 2
// ID ile ürün bulma
function urunBul(id) {
const urun = urunler.find(u => u.id === id);
if (!urun) {
throw new Error(`Ürün #${id} bulunamadı`);
}
return urun;
}
// findLast() / findLastIndex() — sondan arar (ES2023)
const sayilar = [2, 4, 6, 8, 10, 3, 5];
const sonCift = sayilar.findLast(n => n % 2 === 0);
console.log(sonCift); // 10 — sondan ilk çift sayısome() ve every()
Bu metotlar koşul kontrolleri için kullanılır — dizi elemanlarının en az biri veya hepsi koşulu sağlıyor mu?
const notlar = [85, 72, 90, 68, 95];
// some() — en az BİR eleman koşulu sağlıyor mu?
const kalanVarMi = notlar.some(not => not < 70);
console.log(kalanVarMi); // true — 68 < 70
// every() — TÜM elemanlar koşulu sağlıyor mu?
const hepsiGectiMi = notlar.every(not => not >= 60);
console.log(hepsiGectiMi); // true — en düşük 68 >= 60
// Pratik kullanımlar
const formAlanlari = [
{ isim: "email", deger: "ali@test.com" },
{ isim: "sifre", deger: "123456" },
{ isim: "isim", deger: "" } // Boş alan
];
// Form geçerli mi? (tüm alanlar dolu mu?)
const formGecerli = formAlanlari.every(alan => alan.deger.trim() !== "");
console.log(formGecerli); // false — isim boş
// En az bir boş alan var mı?
const bosAlanVar = formAlanlari.some(alan => alan.deger.trim() === "");
console.log(bosAlanVar); // true
// Yetki kontrolü
const kullaniciYetkileri = ["okuma", "yazma", "düzenleme"];
const gerekliYetkiler = ["okuma", "silme"];
const tumYetkilerVar = gerekliYetkiler.every(yetki =>
kullaniciYetkileri.includes(yetki)
);
console.log(tumYetkilerVar); // false — "silme" yetkisi yok💡 İpucu: some() ve every() erken sonlanır (short-circuit). some() ilk true'da, every() ilk false'ta durur. Bu, büyük dizilerde performans avantajı sağlar.
sort() — Sıralama
sort() diziyi yerinde (in-place) sıralar ve orijinal diziyi değiştirir:
// ❌ TUZAK: sort() varsayılan olarak STRING sıralaması yapar!
const sayilar = [10, 5, 100, 25, 1];
sayilar.sort();
console.log(sayilar); // [1, 10, 100, 25, 5] — ALFABETİK sıralama!
// "10" < "25" < "5" çünkü "1" < "2" < "5" (string karşılaştırma)
// ✅ Sayısal sıralama — karşılaştırma fonksiyonu ile
const dogruSirala = [10, 5, 100, 25, 1];
dogruSirala.sort((a, b) => a - b); // Küçükten büyüğe
console.log(dogruSirala); // [1, 5, 10, 25, 100]
// Büyükten küçüğe
dogruSirala.sort((a, b) => b - a);
console.log(dogruSirala); // [100, 25, 10, 5, 1]Karşılaştırma fonksiyonu nasıl çalışır?
a - b < 0→ a önce gelira - b > 0→ b önce gelira - b === 0→ sıra değişmez
// String sıralama (Türkçe karakter desteği)
const isimler = ["Çiçek", "Ali", "Ömer", "Ayşe", "Ünal", "İbrahim"];
// ❌ Varsayılan sort — Türkçe karakterler sonda
isimler.sort();
console.log(isimler); // ["Ali", "Ayşe", "İbrahim", "Çiçek", "Ömer", "Ünal"] — yanlış!
// ✅ localeCompare ile Türkçe uyumlu sıralama
const turkceIsimler = [...isimler].sort((a, b) =>
a.localeCompare(b, 'tr')
);
console.log(turkceIsimler); // ["Ali", "Ayşe", "Çiçek", "İbrahim", "Ömer", "Ünal"]
// Nesne dizisini sıralama
const urunler = [
{ isim: "Laptop", fiyat: 15000 },
{ isim: "Mouse", fiyat: 250 },
{ isim: "Klavye", fiyat: 500 },
{ isim: "Monitor", fiyat: 8000 }
];
// Fiyata göre artan
const ucuzdanPahaliya = [...urunler].sort((a, b) => a.fiyat - b.fiyat);
console.log(ucuzdanPahaliya.map(u => `${u.isim}: ${u.fiyat} TL`));
// ["Mouse: 250 TL", "Klavye: 500 TL", "Monitor: 8000 TL", "Laptop: 15000 TL"]
// İsme göre alfabetik
const alfabetik = [...urunler].sort((a, b) =>
a.isim.localeCompare(b.isim, 'tr')
);⚠️ Dikkat: sort() orijinal diziyi değiştirir. Orijinal sırayı korumak istiyorsanız, önce kopyalayın: [...dizi].sort() veya ES2023'ün dizi.toSorted() metodunu kullanın.
flat() ve flatMap()
İç içe dizileri düzleştirir:
// flat() — iç içe dizileri düzleştirir
const icice = [1, [2, 3], [4, [5, 6]]];
console.log(icice.flat()); // [1, 2, 3, 4, [5, 6]] — 1 seviye
console.log(icice.flat(2)); // [1, 2, 3, 4, 5, 6] — 2 seviye
console.log(icice.flat(Infinity)); // Tüm seviyeleri düzleştir
// flatMap() — map + flat(1) birleşimi
const cumleler = ["Merhaba Dünya", "JavaScript Kursu", "Harika Gün"];
const kelimeler = cumleler.flatMap(cumle => cumle.split(" "));
console.log(kelimeler); // ["Merhaba", "Dünya", "JavaScript", "Kursu", "Harika", "Gün"]
// flatMap ile filtreleme + dönüştürme
const siparisler = [
{ musteri: "Ali", urunler: ["Laptop", "Mouse"] },
{ musteri: "Ayşe", urunler: ["Telefon"] },
{ musteri: "Can", urunler: ["Tablet", "Kılıf", "Kalem"] }
];
const tumUrunler = siparisler.flatMap(s => s.urunler);
console.log(tumUrunler); // ["Laptop", "Mouse", "Telefon", "Tablet", "Kılıf", "Kalem"]Method Chaining (Metot Zincirleme)
Dizi metotlarının en güçlü kullanımı, birbirine zincirlenmeleridir. Her metot yeni bir dizi döndürdüğü için, sonraki metot bir öncekinin sonucu üzerinde çalışır:
// E-ticaret senaryosu
const urunler = [
{ isim: "Laptop", fiyat: 15000, kategori: "Elektronik", stok: 5 },
{ isim: "Tişört", fiyat: 150, kategori: "Giyim", stok: 0 },
{ isim: "Mouse", fiyat: 250, kategori: "Elektronik", stok: 20 },
{ isim: "Kitap", fiyat: 50, kategori: "Kırtasiye", stok: 100 },
{ isim: "Klavye", fiyat: 500, kategori: "Elektronik", stok: 8 },
{ isim: "Kalem", fiyat: 10, kategori: "Kırtasiye", stok: 500 },
{ isim: "Monitor", fiyat: 8000, kategori: "Elektronik", stok: 0 },
{ isim: "Defter", fiyat: 25, kategori: "Kırtasiye", stok: 200 }
];
// Stokta olan elektronik ürünleri, fiyata göre sırala ve formatla
const sonuc = urunler
.filter(u => u.kategori === "Elektronik") // Sadece elektronik
.filter(u => u.stok > 0) // Stokta olanlar
.sort((a, b) => a.fiyat - b.fiyat) // Ucuzdan pahalıya
.map(u => `${u.isim}: ${u.fiyat.toLocaleString('tr-TR')} TL`); // Formatla
console.log(sonuc);
// ["Mouse: 250 TL", "Klavye: 500 TL", "Laptop: 15.000 TL"]
// Toplam stok değeri hesaplama
const toplamDeger = urunler
.filter(u => u.stok > 0)
.reduce((acc, u) => acc + u.fiyat * u.stok, 0);
console.log(`Toplam stok değeri: ${toplamDeger.toLocaleString('tr-TR')} TL`);
// Kategoriye göre gruplama + istatistik
const kategoriIstatistik = urunler.reduce((acc, u) => {
if (!acc[u.kategori]) {
acc[u.kategori] = { adet: 0, toplamDeger: 0, urunler: [] };
}
acc[u.kategori].adet++;
acc[u.kategori].toplamDeger += u.fiyat * u.stok;
acc[u.kategori].urunler.push(u.isim);
return acc;
}, {});
console.log(kategoriIstatistik);Okunabilirlik İpuçları
// ❌ Çok uzun tek satır — okunması zor
const sonuc1 = urunler.filter(u => u.stok > 0).sort((a, b) => a.fiyat - b.fiyat).map(u => u.isim).slice(0, 3);
// ✅ Her metot kendi satırında — okunabilir
const sonuc2 = urunler
.filter(u => u.stok > 0)
.sort((a, b) => a.fiyat - b.fiyat)
.map(u => u.isim)
.slice(0, 3);
// ✅ Karmaşık callback'leri isimli fonksiyonlara çıkarın
const stoktaMi = u => u.stok > 0;
const ucuzdanPahaliya = (a, b) => a.fiyat - b.fiyat;
const sadecIsim = u => u.isim;
const sonuc3 = urunler
.filter(stoktaMi)
.sort(ucuzdanPahaliya)
.map(sadecIsim)
.slice(0, 3);Diğer Faydalı Metotlar
const dizi = [1, 2, 3, 4, 5];
// slice() — bir bölümünü al (orijinali değiştirmez)
console.log(dizi.slice(1, 3)); // [2, 3] — index 1'den 3'e kadar (3 hariç)
console.log(dizi.slice(-2)); // [4, 5] — sondan 2 eleman
console.log(dizi.slice()); // [1, 2, 3, 4, 5] — tam kopya
// concat() — dizileri birleştir (yeni dizi döndürür)
const a = [1, 2];
const b = [3, 4];
console.log(a.concat(b, [5, 6])); // [1, 2, 3, 4, 5, 6]
// join() — diziden string oluştur
const kelimeler = ["JavaScript", "çok", "güçlü"];
console.log(kelimeler.join(" ")); // "JavaScript çok güçlü"
console.log(kelimeler.join(", ")); // "JavaScript, çok, güçlü"
console.log(kelimeler.join("")); // "JavaScriptçokgüçlü"
// includes() — eleman var mı?
console.log([1, 2, 3].includes(2)); // true
console.log([1, 2, 3].includes(5)); // false
// indexOf() / lastIndexOf() — elemanın index'i
console.log([1, 2, 3, 2, 1].indexOf(2)); // 1 — ilk bulunan
console.log([1, 2, 3, 2, 1].lastIndexOf(2)); // 3 — son bulunan
// fill() — diziyi doldur
console.log(new Array(5).fill(0)); // [0, 0, 0, 0, 0]
console.log([1, 2, 3, 4, 5].fill(9, 2)); // [1, 2, 9, 9, 9] — index 2'den itibaren
// reverse() — diziyi tersine çevir (orijinali değiştirir!)
const ters = [1, 2, 3];
ters.reverse();
console.log(ters); // [3, 2, 1]
// Orijinali korumak için: [...dizi].reverse() veya dizi.toReversed()Performans Değerlendirmesi
// forEach vs for vs for...of — performans sıralaması
// for > for...of > forEach (ama fark çoğu durumda önemsizdir)
// Büyük dizilerde dikkat edilecekler:
const buyukDizi = Array.from({ length: 1000000 }, (_, i) => i);
// ❌ Her adımda yeni dizi oluşturmak — N kez N elemanlı dizi
// buyukDizi.filter(...).map(...).filter(...).map(...)
// Her zincirleme metot yeni bir dizi oluşturur!
// ✅ Tek reduce ile birçok işlemi birleştirmek
const sonuc = buyukDizi.reduce((acc, n) => {
if (n % 2 === 0 && n > 500000) { // filter koşulları
acc.push(n * 2); // map dönüşümü
}
return acc;
}, []);
// Küçük-orta dizilerde (< 10.000 eleman) okunabilirliği performansa tercih edin
// Method chaining daha okunabilir ve genellikle yeterince hızlıdır💡 İpucu: Erken optimizasyon yapmayın. Önce okunabilir kod yazın, performans sorunu olursa optimize edin. Çoğu web uygulamasında dizi boyutları birkaç yüz elemanı geçmez ve method chaining gayet yeterlidir.
Özet
🔹 map() her elemanı dönüştürür, filter() koşula göre eler, reduce() tek değere indirger — bu üçü fonksiyonel programlamanın temelini oluşturur
🔹 find() / findIndex() koşula uyan ilk elemanı/index'ini döndürür; some() en az biri koşulu sağlıyor mu, every() hepsi sağlıyor mu kontrol eder
🔹 sort() orijinal diziyi değiştirir ve varsayılan olarak string sıralaması yapar — sayısal sıralama için
(a, b) => a - bkullanın; Türkçe içinlocaleCompare(b, 'tr')🔹 Method chaining ile metotları birbirine bağlayarak karmaşık veri dönüşümleri zarif bir şekilde yapılabilir — her metodu kendi satırına koyun
🔹 reduce'da başlangıç değerini her zaman belirtin; gruplama, frekans sayma ve pipeline oluşturma gibi ileri kullanımları çok güçlüdür
🔹 Immutable yaklaşımı tercih edin:
sortyerinetoSorted,reverseyerinetoReversed,spliceyerinetoSpliced(ES2023)
AI Asistan
Sorularını yanıtlamaya hazır