`Array` nesnesi
Bu makalede Array nesnesi açıklanmaktadır.
Dizilerin pratik kullanımlarını kolay anlaşılır bir şekilde adım adım açıklayacağım.
YouTube Video
Array nesnesi
JavaScript'teki Array nesnesi, her türlü veri işlemenin temelini oluşturan en önemli yapılardan biridir. Temel dizi işlemlerinden, verimli veri dönüşümü için faydalı olan üst düzey fonksiyonlara kadar bilmeniz gereken birçok özellik vardır.
Dizi Temelleri
JavaScript'te diziler, birden fazla değeri birlikte işlemek için temel bir veri yapısıdır. Burada, dizilerin nasıl oluşturulacağını ve elemanlarının nasıl okunup yazılacağını basit örneklerle açıklıyoruz.
1// Create arrays in different ways
2const arr1 = [1, 2, 3]; // array literal
3const arr2 = new Array(4, 5, 6); // Array constructor
4const arr3 = Array.of(7, 8, 9); // Array.of
5
6console.log("arr1 created with literal. :", arr1);
7console.log("arr2 created with constructor:", arr2);
8console.log("arr3 created with Array.of. :", arr3);
9// arr1 created with literal. : [ 1, 2, 3 ]
10// arr2 created with constructor: [ 4, 5, 6 ]
11// arr3 created with Array.of. : [ 7, 8, 9 ]
12
13// Access and modify elements
14let first = arr1[0]; // read element
15console.log("First element of arr1:", first);
16// First element of arr1: 1
17
18arr1[1] = 20; // modify element
19console.log("arr1 after modifying index 1:", arr1);
20// arr1 after modifying index 1: [ 1, 20, 3 ]
21
22const len = arr1.length; // get length
23console.log("Length of arr1:", len);
24// Length of arr1: 3
- Bu kod, dizileri oluşturmanın üç yolunu, indeks kullanarak öğelerin nasıl okunup güncelleneceğini ve
lengthözelliği ile uzunluğun nasıl alınacağını gösteriyor. - Dizi literal'leri en yaygın ve okunaklı olanlardır ve günlük durumlarda en sık kullanılırlar.
Eleman Ekleme ve Çıkarma (Sonda veya Başta)
Diziler, baştan veya sondan kolayca eleman ekleyip çıkarmanıza olanak tanır. Bu işlemler, yığın (stack) veya kuyruk (queue) gibi yapılar oluştururken de faydalıdır.
1// Push and pop (stack-like)
2const stack = [];
3console.log("Initial stack:", stack);
4
5stack.push(1); // push 1
6console.log("After push(1):", stack);
7
8stack.push(2); // push 2
9console.log("After push(2):", stack);
10
11const last = stack.pop(); // pop -> 2
12console.log("Popped value:", last);
13console.log("Stack after pop():", stack);
14
15// Unshift and shift (queue-like)
16const queue = [];
17console.log("Initial queue:", queue);
18
19queue.push('a'); // add to end
20console.log("After push('a'):", queue);
21
22queue.unshift('start'); // add to front
23console.log("After unshift('start'):", queue);
24
25const firstItem = queue.shift(); // remove from front
26console.log("Shifted value:", firstItem);
27console.log("Queue after shift():", queue);
28
29// Initial stack: []
30// After push(1): [ 1 ]
31// After push(2): [ 1, 2 ]
32// Popped value: 2
33// Stack after pop(): [ 1 ]
34
35// Initial queue: []
36// After push('a'): [ 'a' ]
37// After unshift('start'): [ 'start', 'a' ]
38// Shifted value: start
39// Queue after shift(): [ 'a' ]
pushvepop, bir dizinin sonunda çalışır. Yığın (stack) yapıları oluşturmak için idealdirler.unshiftveshift, bir dizinin başında çalışır. Ancak, başta yapılan işlemler tüm eleman indekslerinin dahili olarak kaydırılmasını gerektirir ve bu da maliyetli bir işlemdir.
Ortadaki Elemanların Yönetilmesi (splice ve slice)
Bir dizinin ortasındaki elemanlarla çalışırken, orijinal diziyi değiştirip değiştirmemek istediğinize göre splice veya slice seçin. Bir dizinin sadece bir kısmını çıkarmak istiyorsanız slice kullanın; dizinin kendisini değiştirmek, örneğin eleman eklemek veya silmek istiyorsanız, splice kullanın.
1// slice (non-destructive)
2const nums = [0, 1, 2, 3, 4];
3console.log("Original nums:", nums);
4
5const part = nums.slice(1, 4); // returns [1, 2, 3]
6console.log("Result of nums.slice(1, 4):", part);
7console.log("nums after slice (unchanged):", nums);
8
9// splice (destructive)
10const arr = [10, 20, 30, 40];
11console.log("\nOriginal arr:", arr);
12
13// remove 1 item at index 2, insert 25 and 27
14arr.splice(2, 1, 25, 27);
15console.log("After arr.splice(2, 1, 25, 27):", arr);
16
17// Original nums: [ 0, 1, 2, 3, 4 ]
18// Result of nums.slice(1, 4): [ 1, 2, 3 ]
19// nums after slice (unchanged): [ 0, 1, 2, 3, 4 ]
20
21// Original arr: [ 10, 20, 30, 40 ]
22// After arr.splice(2, 1, 25, 27): [ 10, 20, 25, 27, 40 ]
slice, yalnızca elemanları çıkarır ve orijinal diziyi değiştirmez.splice, eleman ekler veya çıkarır ve dizinin kendisini değiştirir, bu yüzden davranışa etkisi konusunda dikkatli olun.
Döngü (for / for...of / forEach)
Dizileri sırayla işlemek için birkaç farklı yol vardır ve amacınıza veya kodlama tercihinize göre seçebilirsiniz. İşte üç tipik döngü yapısı.
1const items = ['apple', 'banana', 'cherry'];
2console.log("Items:", items);
3
4// classic for
5console.log("\n--- Classic for loop ---");
6for (let i = 0; i < items.length; i++) {
7 console.log(`Index: ${i}, Value: ${items[i]}`);
8}
9
10// for...of (recommended for values)
11console.log("\n--- for...of loop ---");
12for (const item of items) {
13 console.log(`Value: ${item}`);
14}
15
16// forEach (functional style)
17console.log("\n--- forEach loop ---");
18items.forEach((item, index) => {
19 console.log(`Index: ${index}, Value: ${item}`);
20});fordöngüsü en esnek olanıdır; indeks işlemleri vebreakgibi ifadelerle döngüyü hassas şekilde kontrol etmenizi sağlar.for...of, eleman değerleriyle çalışmanın kısa bir yolunu sunar ve okunabilirlik açısından en dengelilerinden biridir.forEach, fonksiyonel tarzda kod yazımına imkan tanır ve her eleman için loglama veya veri güncelleme gibi yan etki işlemleri için uygundur. Ancak,breakveyacontinuekullanamazsınız veawaitile asenkron işlemler için uygun değildir.
map / filter / reduce — Üst Düzey Fonksiyonlar
map, filter ve reduce, dizileri dönüştürürken, filtrelerken veya birleştirirken sıkça kullanılan yüksek dereceli fonksiyonlardır. Tekrarlayan işlemleri açıkça ifade edebildiğiniz için kodunuz basit ve anlaşılır olur.
1const numbers = [1, 2, 3, 4, 5];
2console.log("Original numbers:", numbers);
3
4// map: transform each item
5const doubled = numbers.map(n => n * 2);
6console.log("\nResult of map (n * 2):", doubled);
7
8// filter: select items
9const evens = numbers.filter(n => n % 2 === 0);
10console.log("Result of filter (even numbers):", evens);
11
12// reduce: accumulate to single value
13const sum = numbers.reduce((acc, n) => acc + n, 0);
14console.log("Result of reduce (sum):", sum);
15
16// Original numbers: [ 1, 2, 3, 4, 5 ]
17// Result of map (n * 2): [ 2, 4, 6, 8, 10 ]
18// Result of filter (even numbers): [ 2, 4 ]
19// Result of reduce (sum): 15
- Bu yöntemler, yapmak istediğiniz işlemi deklaratif bir şekilde ifade etmenizi sağlar, böylece okunabilirliği artırır ve istenmeyen yan etkilerden kaçınmanıza yardımcı olur.
find / findIndex / some / every
İşte arama ve koşul kontrol yöntemlerinin genel bir özeti. Bunlar, belirli koşulları karşılayan elemanları bulmak veya küme üzerinde boolean (doğru/yanlış) kontroller yapmak için faydalıdır.
1const users = [
2 { id: 1, name: 'Alice' },
3 { id: 2, name: 'Bob' },
4 { id: 3, name: 'Carol' }
5];
6
7console.log("Users:", users);
8
9// Find the first user whose name is 'Bob'
10const bob = users.find(user => user.name === 'Bob');
11console.log("\nResult of find (name === 'Bob'):", bob);
12
13// Find index of the user whose id is 3
14const indexOfId3 = users.findIndex(user => user.id === 3);
15console.log("Result of findIndex (id === 3):", indexOfId3);
16
17// Check if there exists a user with id = 2
18const hasId2 = users.some(user => user.id === 2);
19console.log("Result of some (id === 2):", hasId2);
20
21// Check if all users have a numeric id
22const allHaveNumericId = users.every(user => typeof user.id === 'number');
23console.log("Result of every (id is number):", allHaveNumericId);
24// Result of find (name === 'Bob'): { id: 2, name: 'Bob' }
25// Result of findIndex (id === 3): 2
26// Result of some (id === 2): true
27// Result of every (id is number): true
find, koşulu sağlayan ilk elemanı döndürür.findIndex, koşulu sağlayan elemanın indeksini döndürür.some, eğer koşulu sağlayan en az bir eleman varsatruedöndürür.every, tüm elemanlar koşulu sağlıyorsatruedöndürür.
Bunların hepsi dizi işlemlerinde çok faydalıdır; duruma uygun kullandığınızda kodunuz kısa ve anlaşılır olur.
Sıralama ve Karşılaştırma Fonksiyonları
Diziler sort ile sıralanır, ancak varsayılan olarak elemanları string (metin) olarak karşılaştırır, bu nedenle sayıları sıralarken beklenmedik sonuçlar ortaya çıkabilir.
1const nums = [10, 2, 33, 4];
2console.log("Original nums:", nums);
3
4// Default sort: compares elements as strings (not suitable for numbers)
5nums.sort();
6console.log("\nAfter default sort (string comparison):", nums);
7
8// Numeric ascending sort using a compare function
9nums.sort((a, b) => a - b);
10console.log("After numeric sort (a - b):", nums);
11
12// Sort objects by a property
13const people = [{ age: 30 }, { age: 20 }, { age: 25 }];
14console.log("\nOriginal people:", people);
15
16people.sort((a, b) => a.age - b.age);
17console.log("After sorting people by age:", people);
18
19// After default sort (string comparison): [ 10, 2, 33, 4 ]
20// After numeric sort (a - b): [ 2, 4, 10, 33 ]
21// Original people: [ { age: 30 }, { age: 20 }, { age: 25 } ]
22// After sorting people by age: [ { age: 20 }, { age: 25 }, { age: 30 } ]
- Sayıları veya nesneleri sıralarken, onları istediğiniz sıraya göre sıralamak için mutlaka bir karşılaştırma fonksiyonu belirtin.
- Bir karşılaştırma fonksiyonunda, negatif dönüş
ayıb'den önce, pozitif isebyiadan önce, 0 ise sıralamayı değiştirmez.
Dizi Kopyalama ve Değişmezlik
Dizileri kopyalarken, 'referans kopyalama' ile 'yüzeysel kopyalama' arasındaki farkı anlamak önemlidir. Özellikle, dizinin içinde nesneler varsa, yüzeysel bir kopyanın iç nesnelerin paylaşılmasına sebep olacağını unutmayın.
Referans kopyası
Bir diziyi başka bir değişkene atadığınızda, dizinin kendisi çoğaltılmaz; bunun yerine aynı diziye işaret eden 'referans' kopyalanır.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Reference copy; modifying b also affects a
5const b = a;
6console.log("\nReference copy b = a:", b);
7// Reference copy b = a: [ 1, 2, 3 ]
8
9b[0] = 100;
10console.log("After modifying b[0] = 100:");
11console.log("a:", a); // a: [ 100, 2, 3 ] (affected)
12console.log("b:", b); // b: [ 100, 2, 3 ]
- Referans kopyası ile, kopyalanan değişkenle dizinin içeriğini değiştirirseniz, bu değişiklikler aynı diziye işaret eden orijinal değişkene de yansır.
Yüzeysel kopya
slice() veya yayma (spread) sözdizimi kullanmak 'yüzeysel kopya' oluşturur çünkü yalnızca değerler çoğaltılır; orijinal ve kopyalanan diziler ayrı varlıklar olarak ele alınır.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Shallow copy (new array)
5const b = a.slice();
6console.log("\nShallow copy using slice():", b);
7// Shallow copy using slice(): [ 100, 2, 3 ]
8
9const c = [...a];
10console.log("Shallow copy using spread [...a]:", c);
11// Shallow copy using spread [...a]: [ 100, 2, 3 ]
12
13// Modifying c or d does NOT affect a
14b[1] = 200;
15c[2] = 300;
16console.log("\nAfter modifying b[1] = 200 and c[2] = 300:");
17console.log("a:", a); // [ 100, 2, 3 ]
18console.log("b:", b); // [ 100, 200, 3 ]
19console.log("c:", c); // [ 100, 2, 300 ]
- Bu kod,
slice()veya yayma sözdizimi ile oluşturulan bir dizinin yüzeysel kopyasının orijinal diziyi etkilemediğini gösterir.
Yüzeysel kopya ve değişmezlik
'Yüzeysel kopya' ile bir diziyi çoğaltsanız bile, dizinin içinde nesneler varsa istemeden paylaşım gerçekleşebilir.
1// Shallow copy doesn't clone inner objects
2const nested = [{ x: 1 }, { x: 2 }];
3console.log("\nOriginal nested:", nested);
4// Original nested: [ { x: 1 }, { x: 2 } ]
5
6const shallow = nested.slice();
7console.log("Shallow copy of nested:", shallow);
8// Shallow copy of nested: [ { x: 1 }, { x: 2 } ]
9
10// Changing inner object affects both arrays
11shallow[0].x = 99;
12console.log("\nAfter shallow[0].x = 99:");
13console.log("nested:", nested);
14console.log("shallow:", shallow);
15// nested: [ { x: 99 }, { x: 2 } ]
16// shallow: [ { x: 99 }, { x: 2 } ]
- Bu kod, yüzeysel kopyada iç nesnelerin paylaşıldığını ve bu iç nesnelerde yapılan değişikliklerin hem orijinal diziye hem de kopyaya etki ettiğini gösterir.
- Bağımsız verilere ihtiyacınız varsa,
structuredClone()veya JSON dönüşümü gibi bir 'derin kopya' yapmanız gerekir.
Faydalı yardımcı metotlar
Aşağıdakiler, dizilerle çalışırken sıkça kullanılan yardımcı metotlardır. Amaçlarınıza uygun şekilde kullanarak kısa ve okunabilir kodlar yazabilirsiniz.
includes
includes metodu, belirli bir değerin bir dizi içinde olup olmadığını kontrol eder.
1// includes: check if array contains a value
2const letters = ['a', 'b', 'c'];
3const hasB = letters.includes('b');
4console.log("letters:", letters); // [ 'a', 'b', 'c' ]
5console.log("letters.includes('b'):", hasB); // true
- Bu kodda,
includesmetodu belirli bir değerin dizi içinde olup olmadığını kısa şekilde belirlemek için kullanılmıştır.
concat
concat metodu, belirli bir dizi veya değerleri sona ekleyerek yeni bir dizi döndürür ve orijinal diziyi değiştirmez.
1// concat: merge arrays without mutation
2const a1 = [1, 2];
3const a2 = [3, 4];
4const combined = a1.concat(a2);
5console.log("a1.concat(a2):", combined); // [ 1, 2, 3, 4 ]
6console.log("a1(unchanged):", a1); // [ 1, 2 ]
- Bu kod,
concatmetodunun orijinal dizi korunarak yeni bir dizi oluşturmamıza olanak tanıyan yıkıcı olmayan bir işlem olduğunu gösterir.
flat
flat metodu kullanılarak, iç içe geçmiş diziler düzleştirilebilir.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const nested = [1, [2, [3]]];
3console.log("nested:", nested); // nested: [ 1, [ 2, [ 3 ] ] ]
4console.log("nested.flat():", nested.flat()); // default depth = 1
5// nested.flat(): [ 1, 2, [ 3 ] ]
- Bu kod, bir dizinin bir seviye düzleştirilmesinin sonucunu gösterir.
flatyöntemiyle derinliği belirtebildiğiniz için, ihtiyaçlarınıza göre esnekçe iç içe dizileri çözebilirsiniz.
flatMap
flatMap metodu, her bir elemana bir dönüşüm uyguladıktan sonra sonuçları otomatik olarak tek boyutlu bir diziye düzleştirir.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const words = ['hello world', 'hi'];
3console.log("words:", words); // [ 'hello world', 'hi' ]
4
5const splitWords = words.flatMap(w => w.split(' '));
6console.log("words.flatMap(w => w.split(' ')):", splitWords);
7// words.flatMap(w => w.split(' ')): [ 'hello', 'world', 'hi' ]
- Bu kod, bir dizideki her bir dizgenin boşluk karakterine göre bölünüp, elde edilen sonuçların bir araya getirilip tek bir diziye düzleştirildiği bir örnek gösterir.
join
join metodu, bir dizinin öğelerini belirtilen bir ayırıcıyla birleştirerek bir dize oluşturur.
1// join: combine elements into a string with a separator
2const csv = ['a', 'b', 'c'].join(',');
3console.log("['a', 'b', 'c'].join(','):", csv); // a,b,c
- Bu kodda,
joinmetodu bir diziyi virgülle ayrılmış bir dizeye dönüştürmek için kullanılmıştır.
Yaygın Hatalar
Dizi işlemleri ilk bakışta basit görünebilir, fakat kolayca istenmeyen davranışlara yol açabilecek bazı noktalar vardır. Günlük dizi işlemleri sırasında gözden kaçabilecek birçok hata vardır, bu yüzden aşağıdaki noktalara dikkat etmek kodunuzun güvenilirliğini büyük ölçüde artıracaktır.
- Varsayılan olarak,
Array'ninsort()metodu metin karşılaştırmasıyla sıralar. Sayıları doğru şekilde sıralamak için her zaman bir karşılaştırma fonksiyonu vermek gerekir. - Dizileri (
sliceveya spread (yayma) sözdizimi ile) kopyalamak yüzeysel bir kopya oluşturur. Dizileriniz nesneler içeriyorsa dikkatli olun; orijinal veriler farkında olmadan değiştirilebilir. splice, diziyi doğrudan değiştiren yıkıcı (destructive) bir yöntemdir;sliceise orijinal diziyi değiştirmeyen yıkıcı olmayan (non-destructive) bir yöntemdir. Onları ihtiyacınıza uygun olarak kullanmak önemlidir.forEachawaitile asenkron işlemler yapılan döngüler için uygun değildir. Asenkron işlemleri sırayla güvenli şekilde yürütmek istiyorsanızfor...ofkullanmanız önerilir.
Pratik Örnek
Aşağıda, kullanıcı verilerinden toplam yaşı almak, yaşı 30 ve üzeri olanları çıkarıp isim listesini oluşturmak için dizi metotlarının birleştirildiği bir örnek verilmiştir.
1const users = [
2 { name: 'Alice', age: 28 },
3 { name: 'Bob', age: 34 },
4 { name: 'Carol', age: 41 },
5 { name: 'Dave', age: 19 }
6];
7
8console.log("Users:", users);
9
10// sum ages
11const totalAge = users.reduce((acc, u) => acc + u.age, 0);
12console.log("\nTotal age of all users:", totalAge);
13// Total age of all users: 122
14
15// filter and map names of users 30 and older
16const namesOver30 = users
17 .filter(u => u.age >= 30)
18 .map(u => u.name);
19
20console.log("Users aged 30 or older (names):", namesOver30);
21// Users aged 30 or older (names): [ 'Bob', 'Carol' ]
reduce,filtervemapmetotlarını zincirleyerek, veri toplama, koşul ile çıkarma ve dönüştürme işlemlerini kolayca yazabilirsiniz.- Bu tür bir 'veri işleme hattı' yüksek okunabilirliğe sahiptir ve az yan etki barındıran bir tarz olarak gerçek uygulamalarda sıkça kullanılır.
Özet
JavaScript dizileriyle, temel işlemler bile gayet geniş bir yelpazede uygulanabilir ve üst düzey fonksiyonlar kullanıldığında kodunuz daha kısa ve etkili olur. Anlaşılması gereken çok nokta var, fakat her birini uygun biçimde kullanmayı öğrendiğinizde veri işleme çok daha kolay hale gelecektir.
Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.