JavaScript Array'leri: push, pop, slice, splice, Spread ve sort Tuzağı
Array oluşturmayı, at() ile erişimi, push/pop/shift/unshift'i, slice ile splice farkını, spread ile kopyalamayı, forEach'i, sort'un sayıları neden yanlış sıraladığını ve referans tuzağını öğreniyoruz.
Sürüm notu: Bu yazıdaki kodlar ES2026 ve güncel tarayıcılar (Chrome, Edge, Firefox, Safari) içindir.
Önce Tahmin Et
Bu yazının konusu array'ler, yani değerleri sıralı bir liste hâlinde tutan yapı. Başlamadan önce şu üç satıra bak:
const numbers = [10, 9, 1, 100];
numbers.sort();
console.log(numbers);
sort adı üstünde, sıralıyor. Peki konsolda hangi sıra çıkar? [1, 9, 10, 100] dediysen yalnız değilsin. Okumaya devam etmeden önce tahminini netleştir; cevabı sort bölümünde, motorun aslında neyi karşılaştırdığını gördüğümüzde açıklayacağız.
Array Oluşturmak ve Element'lere Erişmek
Bir array'i bir trenin vagonları gibi düşün. Vagonlar sıra hâlinde dizilir, her birinin bir numarası vardır ve numaralar sıfırdan başlar. Bir array oluşturmanın en yaygın yolu köşeli parantezdir. Bunu tarayıcının konsoluna yapıştırıp dene:
const fruits = ["apple", "pear", "banana"];
const empty = [];
const mixed = [42, "text", true, null];
console.log(fruits.length); // 3
console.log(empty.length); // 0
console.log(typeof fruits); // "object"
console.log(Array.isArray(fruits)); // true
Bir array'in içine her tipten değer koyabilirsin, hatta karıştırabilirsin. Ama pratikte bir array'de genelde aynı türden şeyler tutulur: ürünler, kullanıcılar, fiyatlar. typeof'un "object" demesi seni şaşırtmasın; daha önce veri tipleri yazısında gördüğümüz gibi array'ler aslında özel bir object türü. Bir değerin array olup olmadığını öğrenmek için Array.isArray kullan.
Element'lere ulaşmak, string'lerden tanıdığın yöntemle aynı: köşeli parantez içinde index, sondan saymak için ES2022 ile gelen at(). Fark şu ki string'in aksine array'in element'lerini değiştirebilirsin:
const fruits = ["apple", "pear", "banana"];
console.log(fruits[0]); // "apple"
console.log(fruits.at(-1)); // "banana"
console.log(fruits[5]); // undefined
fruits[1] = "cherry";
console.log(fruits); // ["apple", "cherry", "banana"]
Burada bir şey dikkatini çekmiş olabilir: fruits bir const, ama içini değiştirebildik. Daha önce değişkenler yazısında gördüğümüz yeniden atama ile mutasyon farkı tam olarak bu. const, fruits etiketinin başka bir array'e yapıştırılmasını engeller; etiketin yapıştığı array'in içinde olanlara karışmaz.
Element Eklemek ve Çıkarmak
Array'in başına ve sonuna element eklemek ya da çıkarmak için dört method var. Akılda tutmanın kolay yolu şu: push ve pop sonla, unshift ve shift başla çalışır.
const queue = ["Alan", "Ada"];
queue.push("Grace"); // sona ekler
console.log(queue); // ["Alan", "Ada", "Grace"]
queue.unshift("Linus"); // başa ekler
console.log(queue); // ["Linus", "Alan", "Ada", "Grace"]
const last = queue.pop(); // sondakini çıkarır
const first = queue.shift(); // baştakini çıkarır
console.log(last, first); // "Grace" "Linus"
console.log(queue); // ["Alan", "Ada"]
Dönüş değerlerine dikkat et. pop ve shift çıkardıkları element'i geri verir, bu yüzden onu bir değişkene alabildik. push ve unshift ise array'in yeni uzunluğunu döner. Dördü de orijinal array'i değiştirir.
Küçük bir performans notu: sona ekleyip sondan çıkarmak hızlıdır, çünkü diğer element'lere dokunmak gerekmez. Başa element eklediğinde ya da baştan çıkardığında ise motor geri kalan bütün element'lerin numarasını bir kaydırmak zorunda kalır. Birkaç bin element'e kadar bunu hissetmezsin, ama milyonlarca element'li bir array'de fark eder.
Array'de Arama: includes ve indexOf
String'lerden hatırladığın iki method array'lerde de var ve aynı mantıkla çalışır:
const colors = ["red", "green", "blue"];
console.log(colors.includes("green")); // true
console.log(colors.indexOf("blue")); // 2
console.log(colors.indexOf("purple")); // -1
console.log([NaN].includes(NaN)); // true
console.log([NaN].indexOf(NaN)); // -1
ES2016 ile gelen includes "var mı?", indexOf ise "nerede?" sorusunu cevaplar. Son iki satır ikisi arasındaki küçük ama gerçek bir farkı gösteriyor. indexOf, daha önce gördüğümüz === ile karşılaştırır ve NaN kendisine eşit olmadığı için onu asla bulamaz. includes ise NaN'ı doğru tanır. Var mı yok mu sorusu için yine includes'u tercih et.
slice ve splice: İsim İkiz, Huy Değil
Bu iki method neredeyse aynı yazılır ama karakterleri bambaşka. slice fotoğrafçıdır: array'in bir bölümünün kopyasını çeker, aslına dokunmaz. splice ise cerrahtır: array'in üzerinde bizzat ameliyat yapar, keser, çıkarır, yerine yenisini diker.
const letters = ["a", "b", "c", "d", "e"];
const part = letters.slice(1, 3);
console.log(part); // ["b", "c"]
console.log(letters); // ["a", "b", "c", "d", "e"]
slice, string'lerdeki kardeşiyle aynı kuralla çalışır: başlangıç dahil, bitiş hariç, negatif değerler sondan sayar. Orijinal array olduğu gibi duruyor. Şimdi cerrahı izleyelim:
const letters = ["a", "b", "c", "d", "e"];
const removed = letters.splice(1, 2);
console.log(removed); // ["b", "c"]
console.log(letters); // ["a", "d", "e"]
letters.splice(1, 0, "x", "y");
console.log(letters); // ["a", "x", "y", "d", "e"]
splice'ın ilk argümanı başlangıç index'i, ikincisi kaç element silineceği. Bu ikisinden sonra verdiğin her şey o noktaya eklenir. Silinecek sayıyı 0 verirsen hiçbir şey silmeden araya element sokmuş olursun. Dönüş değeri her zaman silinen element'lerden oluşan bir array'dir. Orijinali değiştirmeden aynı işi yapan ES2023'teki toSpliced'ı Orta seride göreceğiz.
join, concat ve Spread
join, daha önce string'ler yazısında gördüğümüz split'in tersidir: array'in element'lerini verdiğin ayırıcıyla birleştirip tek bir string yapar.
const words = ["JavaScript", "is", "fun"];
console.log(words.join(" ")); // "JavaScript is fun"
console.log(words.join(", ")); // "JavaScript, is, fun"
console.log(["2026", "11", "03"].join("-")); // "2026-11-03"
İki array'i birleştirmek için concat var. Orijinalleri değiştirmez, yeni bir array döner. Ama modern kodda bunu daha sık, ES2015 ile gelen spread syntax'ıyla (...) görürsün. Üç nokta, bir array'in element'lerini olduğu yere tek tek dökmek demek:
const fruits = ["apple", "pear"];
const vegetables = ["carrot", "spinach"];
console.log(fruits.concat(vegetables)); // ["apple", "pear", "carrot", "spinach"]
console.log([...fruits, ...vegetables]); // aynı sonuç
console.log(["cherry", ...fruits, "fig"]); // ["cherry", "apple", "pear", "fig"]
const copy = [...fruits];
copy.push("banana");
console.log(fruits); // ["apple", "pear"]
console.log(copy); // ["apple", "pear", "banana"]
Son kısım önemli: [...fruits] ile yeni bir array oluşturduk, bu yüzden copy'ye eklenen element fruits'u etkilemedi. Bunun neden önemli olduğunu tuzaklar bölümünde göreceğiz. Spread'in object'lerle kullanımını object'ler yazısında, diğer marifetlerini ise Orta seride göreceğiz.
forEach ile İlk Tanışma
Daha önce döngüler yazısında bir array'i for...of ile gezmeyi görmüştük. Array'lerin bunun için kendi method'u da var: forEach. Ona bir fonksiyon verirsin, o da her element için bu fonksiyonu çağırır:
const prices = [120, 45, 300];
prices.forEach((price, index) => {
console.log(`Item ${index + 1}: ${price} TL`);
});
// Item 1: 120 TL
// Item 2: 45 TL
// Item 3: 300 TL
(price, index) => { ... } kısmı bir arrow function. Fonksiyonları bir sonraki yazıda bütün ayrıntısıyla göreceğiz; şimdilik şöyle oku: "her element için bana o element'i ve index'ini ver, ben de süslü parantezin içindekini yapayım". Bir fonksiyona başka bir fonksiyonu böyle vermeye callback denir.
forEach mi, for...of mu? İkisi de iş görür. Tek önemli fark: forEach'in ortasında break ile çıkamazsın, her element'i mutlaka dolaşır. Bir koşul sağlandığında durman gerekiyorsa for...of kullan. Array'lerin map, filter ve reduce gibi daha güçlü method'larını ise Orta seride derinlemesine ele alacağız.
sort: Sıralamanın Gizli Kuralı
Baştaki sorunun cevabı: [1, 10, 100, 9].
Bu sonuç ilk görüşte hata gibi duruyor ama değil. sort'a nasıl sıralayacağını söylemezsen, element'leri önce string'e çevirir ve onları sözlükteki gibi karakter karakter karşılaştırır. Sözlükte "10", "9"'dan önce gelir, çünkü ilk karakterler olan "1" ile "9" karşılaştırılır ve orada iş biter. Telefon rehberinde isimlerin dizilişi gibi düşün.
Sayıları sayı olarak sıralamak için sort'a bir karşılaştırma fonksiyonu verirsin. Bu fonksiyon iki element alır ve bir sayı döner: negatifse a öne, pozitifse b öne geçer, sıfırsa sıraları korunur. a - b tam olarak bunu yapar:
const numbers = [10, 9, 1, 100];
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 9, 10, 100]
numbers.sort((a, b) => b - a);
console.log(numbers); // [100, 10, 9, 1]
Türkçe kelimelerde de benzer bir sürpriz var. Varsayılan sıralama karakterlerin Unicode sırasına bakar ve orada "ç", "ş", "ü" gibi harfler "z"'nin arkasında kalır. Doğru alfabetik sıra için localeCompare'i o dilin koduyla kullan:
const fruits = ["şeftali", "armut", "çilek", "üzüm", "zeytin"];
console.log([...fruits].sort());
// ["armut", "zeytin", "çilek", "üzüm", "şeftali"]
console.log([...fruits].sort((a, b) => a.localeCompare(b, "tr")));
// ["armut", "çilek", "şeftali", "üzüm", "zeytin"]
Burada sıralamadan önce [...fruits] ile kopya aldığımızı fark et. Nedeni bir sonraki bölümde.
Sık Düşülen Tuzaklar
sort orijinali değiştirir
const original = [3, 1, 2];
const sorted = original.sort((a, b) => a - b);
console.log(sorted); // [1, 2, 3]
console.log(original); // [1, 2, 3]
console.log(sorted === original); // true
sort yeni bir array üretmez, elindekini yerinde sıralar ve aynı array'i geri döner. Orijinal sırayı korumak istiyorsan önce spread ile kopyala. ES2023 ile gelen ve orijinale dokunmayan toSorted de var; onu Orta seride diğer kopyalayan method'larla birlikte göreceğiz.
Atama kopyalamaz
const cart = ["pen", "notebook"];
const otherCart = cart;
otherCart.push("eraser");
console.log(cart); // ["pen", "notebook", "eraser"]
console.log(cart === otherCart); // true
console.log([1, 2] === [1, 2]); // false
Bu yazının belki de en önemli kısmı. Daha önce veri tipleri yazısında değer ve referans farkına ilk kez bakmıştık; işte karşımızda. otherCart = cart yazdığında yeni bir array oluşmaz. Aynı eve ikinci bir anahtar çıkarmış olursun. Hangi anahtarla girersen gir, aynı odadaki eşyaları yerinden oynatırsın. Son satır da bunun öbür yüzü: içerikleri aynı olsa bile iki ayrı array literal'i iki ayrı ev demek, === onları farklı sayar. Gerçekten ayrı bir array istiyorsan [...cart] ile kopyala.
Spread sığ bir kopyadır
Spread yalnızca en dış katmanı kopyalar. Array'in içinde başka array'ler ya da object'ler varsa, kopya da aynı iç parçalara işaret eder. Object'leri ve derin kopyayı ilerleyen yazılarda detaylandıracağız; şimdilik düz değerlerden oluşan array'lerde spread'in güvenli olduğunu bilmen yeterli.
Küçük Bir Deneme
★☆☆ Boş bir todos array'i oluştur. push ile üç görev ekle, unshift ile en başa acil bir görev koy, pop ile sonuncusunu çıkar. Her adımdan sonra array'i konsola yazdır ve tahminlerinle karşılaştır.
★★☆ Çalıştırmadan önce tahmin et: const a = [1, 2, 3, 4, 5]; için a.slice(-2) ne döner? Ardından a.splice(1, 3) ne döner ve a'nın son hâli ne olur?
★★☆ [5, 25, 100, 1, 40] array'ini önce varsayılan sort ile, sonra küçükten büyüğe, sonra büyükten küçüğe sırala. Orijinal array'in her seferinde ne hâlde olduğuna bak ve bunu bozmamak için kodunu düzelt.
★★★ "cat,dog,bird,cat,fish,dog" string'ini split ile array'e çevir. Daha önce gördüğümüz bir döngü ve includes kullanarak tekrar edenleri ayıkla, sonucu alfabetik sıraya koy ve join(", ") ile tek satırda yazdır.
Bu yazıda forEach ve sort'a bir fonksiyon verdik ama fonksiyonun ne olduğunu henüz tam konuşmadık. Bir sonraki yazıda fonksiyonlara geçiyoruz: function declaration, expression ve arrow function farkını, parametreleri, return'ü ve bir fonksiyonu neden bir değer gibi elden ele verebildiğimizi göreceğiz.