← Kursa Dön
📄 Text · 30 min

Diziler (Arrays)

Giriş — Koleksiyonların Gücü

Şimdiye kadar tek bir değeri saklayan değişkenlerle çalıştık: bir isim, bir sayı, bir boolean. Ama gerçek dünyada veriler genellikle gruplar halinde gelir — öğrenci listesi, ürün fiyatları, mesajlar, bildirimler. Tüm bu verileri tek tek değişkenlere atamak mantıksız ve sürdürülemez olurdu:

// ❌ Bu şekilde 100 öğrenci için 100 değişken mi tanımlayacağız?
let ogrenci1 = "Ali";
let ogrenci2 = "Ayşe";
let ogrenci3 = "Mehmet";
// ...

İşte diziler (arrays) bu sorunu çözer. Birden fazla değeri sıralı bir koleksiyonda saklamanızı sağlar. Tek bir değişkenle binlerce veriye erişebilir, üzerinde döngü kurabilir, filtreleyebilir, dönüştürebilir ve sıralayabilirsiniz.

Analoji: Bir dizi, numaralı gözleri olan bir posta kutusudur. Her göz bir değeri saklar ve siz göz numarasını (index) kullanarak istediğiniz değere ulaşırsınız. 0 numaralı göz ilk değeri, 1 numaralı göz ikinci değeri saklar... Bu posta kutusuna yeni gözler ekleyebilir, mevcut gözlerden posta alabilir veya gözleri yeniden düzenleyebilirsiniz.


Dizi Oluşturma

JavaScript'te dizi oluşturmanın birkaç yolu vardır:

Dizi Literali (En Yaygın)

// Boş dizi
const bosArray = [];

// Değerlerle dolu dizi
const meyveler = ["elma", "armut", "portakal"];
const sayilar = [1, 2, 3, 4, 5];
const karisik = ["Ali", 25, true, null, { sehir: "İstanbul" }];

// Diziler farklı tipleri barındırabilir — ama genellikle aynı tipte tutulur
// TypeScript kullandığınızda tip güvenliği bunu zorunlu kılabilir

Array Constructor

// Constructor ile oluşturma (nadir kullanılır)
const dizi1 = new Array(5);           // 5 elemanlı boş dizi (her eleman undefined)
const dizi2 = new Array(1, 2, 3);     // [1, 2, 3]

// ⚠️ Dikkat: tek sayı parametresi uzunluk, birden fazla parametre elemanlar!
console.log(new Array(3));     // [<3 empty items>] — 3 boş yuva
console.log(new Array(3, 4));  // [3, 4] — iki elemanlı dizi

Array.of() ve Array.from()

// Array.of() — constructor'ın tuzağından kaçınır
const dizi3 = Array.of(5);       // [5] — tek elemanlı
const dizi4 = Array.of(1, 2, 3); // [1, 2, 3]

// Array.from() — iterable'ları diziye çevirir
const harfler = Array.from("Merhaba"); // ["M", "e", "r", "h", "a", "b", "a"]

// NodeList'i diziye çevirme (DOM'da çok kullanılır)
// const elementler = Array.from(document.querySelectorAll("div"));

// İkinci parametre: map fonksiyonu
const kareler = Array.from({ length: 5 }, (_, i) => (i + 1) ** 2);
console.log(kareler); // [1, 4, 9, 16, 25]

// 1-10 arası sayı dizisi oluşturma
const birdenOna = Array.from({ length: 10 }, (_, i) => i + 1);
console.log(birdenOna); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Elemanlara Erişim (Read)

Dizilerde elemanlara index ile erişilir. Index 0'dan başlar:

const renkler = ["kırmızı", "mavi", "yeşil", "sarı", "mor"];

// Index ile erişim
console.log(renkler[0]);  // "kırmızı" — ilk eleman
console.log(renkler[2]);  // "yeşil" — üçüncü eleman
console.log(renkler[4]);  // "mor" — son eleman

// Negatif index? Çalışmaz (undefined döner)
console.log(renkler[-1]); // undefined

// at() metodu — negatif index destekler (ES2022)
console.log(renkler.at(0));   // "kırmızı"
console.log(renkler.at(-1));  // "mor" — sondan birinci!
console.log(renkler.at(-2));  // "sarı" — sondan ikinci

// Uzunluk (length)
console.log(renkler.length); // 5

// Son elemana erişim — klasik vs modern
console.log(renkler[renkler.length - 1]); // "mor" — eski yöntem
console.log(renkler.at(-1));              // "mor" — modern yöntem

⚠️ Dikkat: Var olmayan bir index'e erişim hata vermez, undefined döner. Bu, hataları sessizce gizleyebilir:

const dizi = [1, 2, 3];
console.log(dizi[10]); // undefined — hata yok, ama veri de yok
// Çözüm: Erişmeden önce index kontrolü yapın
if (index >= 0 && index < dizi.length) {
  console.log(dizi[index]);
}

CRUD Operasyonları

Eleman Ekleme (Create)

const meyveler = ["elma", "armut"];

// push() — sona ekler, yeni uzunluğu döndürür
let yeniUzunluk = meyveler.push("portakal");
console.log(meyveler);     // ["elma", "armut", "portakal"]
console.log(yeniUzunluk);  // 3

// Birden fazla eleman ekleyebilir
meyveler.push("muz", "kivi");
console.log(meyveler); // ["elma", "armut", "portakal", "muz", "kivi"]

// unshift() — başa ekler
meyveler.unshift("çilek");
console.log(meyveler); // ["çilek", "elma", "armut", "portakal", "muz", "kivi"]

// splice(index, 0, eleman) — belirli bir konuma ekler
meyveler.splice(2, 0, "ananas"); // Index 2'ye ekle, 0 eleman sil
console.log(meyveler); // ["çilek", "elma", "ananas", "armut", "portakal", "muz", "kivi"]

Eleman Silme (Delete)

const hayvanlar = ["kedi", "köpek", "kuş", "balık", "tavşan"];

// pop() — sondan siler, silinen elemanı döndürür
let sonEleman = hayvanlar.pop();
console.log(sonEleman);  // "tavşan"
console.log(hayvanlar);  // ["kedi", "köpek", "kuş", "balık"]

// shift() — baştan siler
let ilkEleman = hayvanlar.shift();
console.log(ilkEleman);  // "kedi"
console.log(hayvanlar);  // ["köpek", "kuş", "balık"]

// splice(index, adet) — belirli konumdan belirli adette siler
hayvanlar.splice(1, 1); // Index 1'den 1 eleman sil
console.log(hayvanlar);  // ["köpek", "balık"]

// splice ile silme + ekleme aynı anda
const renkler = ["kırmızı", "yeşil", "mavi"];
renkler.splice(1, 1, "sarı", "turuncu"); // Index 1'den 1 sil, yerine 2 ekle
console.log(renkler); // ["kırmızı", "sarı", "turuncu", "mavi"]

💡 İpucu: push/pop (sondaki işlemler) unshift/shift'ten (baştaki işlemler) çok daha hızlıdır. Başa ekleme/silme yapıldığında tüm elemanların indexleri kaydırılması gerekir — büyük dizilerde performans farkı belirginleşir.

Eleman Güncelleme (Update)

const notlar = [70, 85, 60, 90, 75];

// Index ile doğrudan güncelleme
notlar[2] = 95; // Üçüncü notu 60'tan 95'e değiştir
console.log(notlar); // [70, 85, 95, 90, 75]

// Koşullu güncelleme
for (let i = 0; i < notlar.length; i++) {
  if (notlar[i] < 75) {
    notlar[i] = 75; // 75'in altındaki notları 75'e yükselt
  }
}
console.log(notlar); // [75, 85, 95, 90, 75]

Arama (Read)

const sehirler = ["İstanbul", "Ankara", "İzmir", "Bursa", "Antalya"];

// indexOf() — ilk bulunan index'i döndürür, bulamazsa -1
console.log(sehirler.indexOf("İzmir"));    // 2
console.log(sehirler.indexOf("Trabzon"));  // -1 (bulunamadı)

// includes() — var mı yok mu (boolean)
console.log(sehirler.includes("Ankara"));  // true
console.log(sehirler.includes("Trabzon")); // false

// find() — koşula uyan İLK elemanı döndürür
const sayilar = [3, 7, 12, 5, 18, 2];
const ilkBuyuk = sayilar.find(n => n > 10);
console.log(ilkBuyuk); // 12

// findIndex() — koşula uyan ilk elemanın index'ini döndürür
const index = sayilar.findIndex(n => n > 10);
console.log(index); // 2

// findLast() / findLastIndex() — sondan başlayarak arar (ES2023)
const sonBuyuk = sayilar.findLast(n => n > 10);
console.log(sonBuyuk); // 18

Dizi İterasyonu (Döngüler)

Dizi elemanları üzerinde gezinmenin birçok yolu vardır:

const urunler = ["Laptop", "Telefon", "Tablet", "Kulaklık"];

// 1. for döngüsü — index'e ihtiyaç varsa
for (let i = 0; i < urunler.length; i++) {
  console.log(`${i + 1}. ${urunler[i]}`);
}

// 2. for...of — en temiz sözdizimi
for (const urun of urunler) {
  console.log(urun);
}

// 3. for...of + entries() — index + değer
for (const [index, urun] of urunler.entries()) {
  console.log(`${index}: ${urun}`);
}

// 4. forEach() — dizi metodu (return/break çalışmaz!)
urunler.forEach((urun, index) => {
  console.log(`${index + 1}. ${urun}`);
});

⚠️ Dikkat: forEach içinde break veya return kullanarak döngüden çıkamazsınız. return sadece o callback'ten çıkar, döngüyü durdurmaz. Döngüyü erken sonlandırmanız gerekiyorsa for veya for...of kullanın:

// ❌ forEach'te break çalışmaz
// urunler.forEach(urun => {
//   if (urun === "Tablet") break; // SyntaxError!
// });

// ✅ for...of ile erken çıkış
for (const urun of urunler) {
  if (urun === "Tablet") break;
  console.log(urun); // "Laptop", "Telefon"
}

Destructuring (Yapı Bozma) — ES6

Destructuring, dizi elemanlarını tek tek değişkenlere atamayı kolaylaştırır:

// Temel destructuring
const koordinat = [41.0082, 28.9784];
const [enlem, boylam] = koordinat;
console.log(enlem);  // 41.0082
console.log(boylam); // 28.9784

// Eleman atlama
const renkler = ["kırmızı", "mavi", "yeşil", "sarı"];
const [birinci, , ucuncu] = renkler; // İkinci atlandı
console.log(birinci); // "kırmızı"
console.log(ucuncu);  // "yeşil"

// Varsayılan değer
const [a, b, c = "yok"] = [1, 2];
console.log(c); // "yok" — dizi 2 elemanlı, c varsayılan alır

// Rest ile kalan elemanları toplama
const [ilk, ...geriKalan] = [10, 20, 30, 40, 50];
console.log(ilk);        // 10
console.log(geriKalan);  // [20, 30, 40, 50]

// Değişken değiştirme (swap) — destructuring ile
let x = "A";
let y = "B";
[x, y] = [y, x];
console.log(x, y); // "B", "A" — geçici değişken gerekmedi!

// Fonksiyondan dizi döndürme + destructuring
function minMax(dizi) {
  return [Math.min(...dizi), Math.max(...dizi)];
}

const [minimum, maksimum] = minMax([5, 3, 8, 1, 9]);
console.log(`Min: ${minimum}, Max: ${maksimum}`); // "Min: 1, Max: 9"

Spread Operatörü (...) — ES6

Spread operatörü, bir diziyi "açarak" elemanlarını tek tek yayar:

// Dizi kopyalama (shallow copy)
const orijinal = [1, 2, 3];
const kopya = [...orijinal];
kopya.push(4);
console.log(orijinal); // [1, 2, 3] — değişmedi!
console.log(kopya);    // [1, 2, 3, 4]

// Dizileri birleştirme (concat alternatifi)
const meyveler = ["elma", "armut"];
const sebzeler = ["domates", "biber"];
const hepsi = [...meyveler, ...sebzeler, "portakal"];
console.log(hepsi); // ["elma", "armut", "domates", "biber", "portakal"]

// Fonksiyon çağrısında
const sayilar = [5, 3, 8, 1, 9];
console.log(Math.max(...sayilar)); // 9 — Math.max(5, 3, 8, 1, 9)

// Dizi içine koşullu eleman ekleme
const rol = "admin";
const menu = [
  "Ana Sayfa",
  "Profil",
  ...(rol === "admin" ? ["Admin Panel", "Kullanıcı Yönetimi"] : []),
  "Ayarlar"
];
console.log(menu);
// admin ise: ["Ana Sayfa", "Profil", "Admin Panel", "Kullanıcı Yönetimi", "Ayarlar"]

⚠️ Dikkat: Spread operatörü yüzeysel (shallow) kopya oluşturur. İç içe diziler veya nesneler referans olarak kopyalanır:

const icice = [[1, 2], [3, 4]];
const kopya = [...icice];

kopya[0].push(99); // İç dizi REFERANS ile kopyalandı!
console.log(icice[0]); // [1, 2, 99] — orijinal de değişti!

// Derin kopya gerekiyorsa:
const derinKopya = JSON.parse(JSON.stringify(icice)); // Basit ama yavaş
// veya: structuredClone(icice) — modern yöntem (ES2022)

Gerçek Dünya Örneği: Öğrenci Yönetim Sistemi

// Öğrenci yönetim sistemi — CRUD operasyonları
const ogrenciler = [];
let sonrakiId = 1;

// CREATE — Öğrenci ekle
function ogrenciEkle(isim, sinif, notlar = []) {
  const ogrenci = {
    id: sonrakiId++,
    isim,
    sinif,
    notlar: [...notlar], // Kopya oluştur
    kayitTarihi: new Date().toISOString().split("T")[0]
  };
  ogrenciler.push(ogrenci);
  return ogrenci;
}

// READ — Tüm öğrencileri listele
function ogrencileriListele() {
  if (ogrenciler.length === 0) {
    console.log("Kayıtlı öğrenci bulunmuyor.");
    return;
  }

  console.log("\n📋 Öğrenci Listesi:");
  console.log("─".repeat(60));

  for (const [index, ogr] of ogrenciler.entries()) {
    const ortalama = ogr.notlar.length > 0
      ? (ogr.notlar.reduce((a, b) => a + b, 0) / ogr.notlar.length).toFixed(1)
      : "N/A";
    console.log(`  ${index + 1}. [${ogr.id}] ${ogr.isim} — ${ogr.sinif} — Ort: ${ortalama}`);
  }
}

// READ — ID ile öğrenci bul
function ogrenciBul(id) {
  return ogrenciler.find(ogr => ogr.id === id) ?? null;
}

// UPDATE — Öğrenciye not ekle
function notEkle(id, ...yeniNotlar) {
  const ogr = ogrenciBul(id);
  if (!ogr) {
    console.error(`Öğrenci #${id} bulunamadı`);
    return;
  }
  ogr.notlar.push(...yeniNotlar);
  console.log(`✅ ${ogr.isim}'e ${yeniNotlar.length} not eklendi`);
}

// DELETE — Öğrenci sil
function ogrenciSil(id) {
  const index = ogrenciler.findIndex(ogr => ogr.id === id);
  if (index === -1) {
    console.error(`Öğrenci #${id} bulunamadı`);
    return;
  }
  const [silinen] = ogrenciler.splice(index, 1);
  console.log(`🗑️ ${silinen.isim} silindi`);
}

// Kullanım
ogrenciEkle("Ali Yılmaz", "10-A", [85, 90, 78]);
ogrenciEkle("Ayşe Kaya", "10-B", [92, 88, 95]);
ogrenciEkle("Mehmet Demir", "10-A");

notEkle(3, 70, 75, 80);
notEkle(1, 95);

ogrencileriListele();
ogrenciSil(2);
ogrencileriListele();

// Sınıfa göre filtreleme
const onASinifi = ogrenciler.filter(ogr => ogr.sinif === "10-A");
console.log("\n10-A sınıfı:", onASinifi.map(o => o.isim).join(", "));

Bu örnekte dizilerin tüm CRUD operasyonlarını, spread, destructuring, find, findIndex, splice, filter, map ve reduce metotlarını gerçek bir senaryoda bir arada kullandık.


Dizi Kopyalama ve Karşılaştırma

Kopyalama

const orijinal = [1, 2, 3];

// Yüzeysel (shallow) kopya yöntemleri — hepsi aynı sonuç
const kopya1 = [...orijinal];           // Spread
const kopya2 = orijinal.slice();        // slice()
const kopya3 = Array.from(orijinal);    // Array.from
const kopya4 = [].concat(orijinal);     // concat

// Derin (deep) kopya
const derin = [[1, 2], [3, 4], { a: 5 }];
const derinKopya = structuredClone(derin); // Modern yöntem (Node 17+, modern tarayıcılar)
derinKopya[0].push(99);
console.log(derin[0]);      // [1, 2] — değişmedi!
console.log(derinKopya[0]); // [1, 2, 99]

Karşılaştırma

// ❌ Diziler referans tiplidir — === referansı karşılaştırır
console.log([1, 2, 3] === [1, 2, 3]); // false!
console.log([] === []);                 // false!

// ✅ İçerik karşılaştırma
function diziEsitMi(a, b) {
  if (a.length !== b.length) return false;
  return a.every((eleman, index) => eleman === b[index]);
}

console.log(diziEsitMi([1, 2, 3], [1, 2, 3])); // true
console.log(diziEsitMi([1, 2, 3], [1, 2, 4])); // false

// Basit yöntem (iç içe yapılarda güvenilmez)
console.log(JSON.stringify([1, 2, 3]) === JSON.stringify([1, 2, 3])); // true

Immutable Array İşlemleri (Değiştirmeden İşlem)

Modern JavaScript, orijinal diziyi değiştirmeden yeni dizi döndüren metotlar sunmaktadır:

const sayilar = [3, 1, 4, 1, 5, 9];

// Mutating (değiştiren) metotlar:
// push, pop, shift, unshift, splice, sort, reverse

// Non-mutating (değiştirmeyen — yeni dizi döndüren) metotlar:
// map, filter, concat, slice, flat, flatMap

// ES2023 — Değiştirmeyen yeni alternatifler
const sirali = sayilar.toSorted();           // sort() yerine
const tersSirali = sayilar.toReversed();     // reverse() yerine
const degistirilmis = sayilar.with(2, 99);   // [2] = 99 yerine

console.log(sayilar);        // [3, 1, 4, 1, 5, 9] — orijinal değişmedi!
console.log(sirali);         // [1, 1, 3, 4, 5, 9]
console.log(tersSirali);     // [9, 5, 1, 4, 1, 3]
console.log(degistirilmis);  // [3, 1, 99, 1, 5, 9]

💡 İpucu: Mümkün olduğunca orijinal diziyi değiştirmeyen (immutable) yöntemleri tercih edin. React, Vue gibi frameworklerde state yönetimi immutability prensibine dayanır. Diziyi doğrudan değiştirmek yerine yeni dizi oluşturmak, birçok bug'ı önler.


Performans İpuçları

Dizilerle çalışırken performans farkı yaratan bazı noktalar:

// 1. push/pop vs unshift/shift
// push/pop: O(1) — sabit süre, son elemanda çalışır
// unshift/shift: O(n) — tüm elemanları kaydırır

const buyukDizi = Array.from({ length: 100000 }, (_, i) => i);

// ✅ Hızlı — sona ekleme
console.time("push");
buyukDizi.push(999999);
console.timeEnd("push"); // ~0.01ms

// ⚠️ Yavaş — başa ekleme (tüm elemanlar kaydırılır)
console.time("unshift");
buyukDizi.unshift(-1);
console.timeEnd("unshift"); // ~2ms (200x daha yavaş)

// 2. for döngüsü vs forEach vs for...of
// Performans farkı modern motorlarda minimal, okunabilirliği öncelikle
// Ama milyon elemanlı dizilerde:
// for > for...of > forEach (küçük fark)

// 3. Büyük dizilerde includes yerine Set kullan
const buyukListe = Array.from({ length: 100000 }, (_, i) => `item_${i}`);
const buyukSet = new Set(buyukListe);

// ❌ Yavaş — O(n) her sorguda
buyukListe.includes("item_99999"); // Diziyi sonuna kadar tarar

// ✅ Hızlı — O(1)
buyukSet.has("item_99999"); // Hash tablosu, anında

// 4. splice ile toplu silme yerine filter kullan
// ❌ splice döngüsü — O(n²)
for (let i = dizi.length - 1; i >= 0; i--) {
  if (dizi[i] % 2 === 0) dizi.splice(i, 1);
}

// ✅ filter — O(n)
const tekSayilar = dizi.filter(n => n % 2 !== 0);

Yaygın Hatalar

1. Referans ile Kopyalama Karışıklığı

// ❌ Diziler referans tiplidir — = ile kopyalanmaz!
const a = [1, 2, 3];
const b = a;        // Aynı diziye referans!
b.push(4);
console.log(a);     // [1, 2, 3, 4] — a da değişti!

// ✅ Kopya oluştur
const c = [...a];   // Yeni dizi
c.push(5);
console.log(a);     // [1, 2, 3, 4] — değişmedi

2. sort() Tuzağı

// ❌ sort() sayıları string olarak sıralar!
const sayilar = [10, 9, 2, 21, 3];
sayilar.sort();
console.log(sayilar); // [10, 2, 21, 3, 9] — YANLIŞ!

// ✅ Karşılaştırma fonksiyonu ver
sayilar.sort((a, b) => a - b);
console.log(sayilar); // [2, 3, 9, 10, 21] — doğru

3. forEach'te Async Kullanmak

// ❌ forEach async callback'leri beklemez!
const urls = ["/api/1", "/api/2", "/api/3"];
urls.forEach(async (url) => {
  const data = await fetch(url); // forEach bunu beklemez
  console.log(data);
});
console.log("Bitti"); // Fetch'ler bitmeden çalışır!

// ✅ for...of ile
for (const url of urls) {
  const data = await fetch(url); // Sırayla bekler
  console.log(data);
}

// ✅ Paralel çalıştırmak istiyorsan
const results = await Promise.all(
  urls.map(url => fetch(url))
);

Özet

  • 🔹 Diziler, sıralı veri koleksiyonlarıdır. Index 0'dan başlar, at(-1) ile sondan erişebilirsiniz

  • 🔹 push/pop (son), unshift/shift (baş), splice (herhangi bir konum) ile CRUD işlemleri yapılır

  • 🔹 Destructuring (const [a, b] = dizi) dizi elemanlarını değişkenlere atamayı kolaylaştırır, rest (...kalan) geriye kalan elemanları toplar

  • 🔹 Spread ([...dizi]) ile yüzeysel kopya oluşturulur ve diziler birleştirilir — iç içe yapılarda structuredClone ile derin kopya kullanın

  • 🔹 forEach içinde break çalışmaz — döngüyü erken sonlandırmak için for...of kullanın

  • 🔹 Orijinal diziyi değiştirmeyen (immutable) metotları tercih edin: toSorted(), toReversed(), with() (ES2023)