JS Array ve Object Manipülasyonu: Map, Filter ve Kopyalama Örnekleri
Bu yazıda, JavaScript'te sık kullanılan dizi ve nesne işlemlerini adım adım örneklerle ele alacağız. Öne çıkan konular: map(), filter(), slice(), nesne kopyalama için Object.assign() ve JSON tabanlı derin kopyalama. Temel tanımlar ve davranışlar için MDN belgelerine ve pratik açıklamalar için Coddy rehberine atıfta bulunacağız.
Referanslar: Array.prototype.map() — MDN, Array.prototype.filter() — MDN, Array.prototype.slice() — MDN, ve Coddy: JavaScript Array Methods.
1) map() ile dönüşüm (map örnekleri)
map() her bir dizi elemanına fonksiyon uygular ve uygulama sonuçlarından yeni bir dizi döndürür. Orijinal diziyi değiştirmez (immutable tarzı dönüşüm sağlar). Bu davranış MDN tarafından tanımlanmıştır.
const nums = [1, 2, 3, 4];
const doubled = nums.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8]
Objelerle birlikte map sıkça kullanılır: bir kullanıcı listesinde sadece isimleri çıkarmak veya yeni bir yapı oluşturmak için:
const users = [{id:1, name:'Ali'}, {id:2, name:'Ayşe'}];
const names = users.map(u => ({ userId: u.id, displayName: u.name.toUpperCase() }));
Kaynak: MDN map.
2) filter() ile eleman seçimi (filter örnekleri)
filter() bir koşula göre dizinin elemanlarını süzer ve koşulu sağlayan elemanlardan oluşan yeni bir dizi döndürür. Orijinal dizi değişmez.
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6]
Objelerle kullanım örneği: aktif kullanıcıları filtrelemek.
const users = [{id:1, active:true}, {id:2, active:false}];
const activeUsers = users.filter(u => u.active);
Kaynak: MDN filter.
3) slice() ile dizi kopyalama ve parçalama
slice(start, end) diziden bir kısmın yeni bir kopyasını döndürür; parametreler opsiyoneldir. Tüm dizinin kopyasını almak için arr.slice() kullanabilirsiniz. Bu da yüzeysel (shallow) bir kopyadır.
const arr = [1, 2, 3, 4];
const copy = arr.slice();
console.log(copy); // [1,2,3,4]
const part = arr.slice(1, 3); // [2,3]
Kaynak: MDN slice.
4) Nesne kopyalama: Object.assign() (yüzeysel kopya)
Object.assign(target, ...sources) kaynak nesnelerin (source) özelliklerini hedef nesneye kopyalar. Genelde yüzeysel kopyalama (shallow copy) yapar; yani iç içe nesnelerin referansları yeni nesnede de paylaşılır. Bu davranış pratik rehberlerde sıkça vurgulanır.
const original = { x: 1, nested: { y: 2 } };
const shallow = Object.assign({}, original);
shallow.nested.y = 99;
console.log(original.nested.y); // 99 — iç içe nesne referansı paylaşıldı
Object.assign() genelde yeni bir nesne oluşturmak ve üst üste yazmak (merge) için kullanılır; hedef nesneyi doğrudan değiştirir. Kaynak: Coddy rehberi.
5) Derin kopyalama: JSON.parse(JSON.stringify())
Basit derin kopyalar için yaygın bir yöntem JSON.parse(JSON.stringify(obj)) kullanmaktır. Bu yaklaşım nesneyi JSON'a çevirip tekrar parse ederek yeni bir nesne üretir; JSON olarak serileştirilebilen yapılar için etkili bir deep copy yöntemidir.
const src = { a: 1, nested: { b: 2 } };
const deep = JSON.parse(JSON.stringify(src));
deep.nested.b = 42;
console.log(src.nested.b); // 2 — üst seviye referanslar ayrıldı
Dikkat: Bu yöntem JSON serileştirmeye uygun olmayan bazı JavaScript değerlerini doğru kopyalamayabilir veya farklı biçimde döndürebilir. Bu nedenle tarih (Date), fonksiyonlar, undefined, Symbol veya Map/Set gibi özel yapılar içeren nesneler için davranış farklı olabilir; daha özel bir derin kopyalama aracı gerektiğinde dikkatli olun. (Genel uygulama rehberleri ve örnekler için: Coddy.)
6) Shallow vs Deep Copy — Kısa Karşılaştırma
| Yöntem | Ne kopyalar | Ne zaman kullanılır | Uyarı |
|---|---|---|---|
| slice() / arr.slice() | Dizi elemanlarının yüzeysel kopyası | Küçük dizileri kopyalamak, parça almak | İç içe referanslar paylaşılır |
| Object.assign() | Nesnenin yüzeysel kopyası / merge | Yüzeysel merge veya yeni nesne oluşturma | Nested nesneler referans olarak kalır |
| JSON.parse(JSON.stringify()) | JSON-uyumlu yapılar için derin kopya | Basit derin kopyalar; küçük/orta yapılar | JSON serileştirilmeyen değerlerde bilgi kaybı olabilir |
7) Pratik örnek: Gerçek bir dönüşüm akışı
Bir kullanıcı dizisinden aktif, 18+ kullanıcıları seçip yeni bir data gönderimi için kopyalamak:
const users = [ { id:1, name:'Ali', age:20, active:true }, { id:2, name:'Veli', age:16, active:true }, { id:3, name:'Ayse', age:30, active:false } ]; const filtered = users .filter(u => u.active && u.age >= 18) // seçme (filter) .map(u => ({ id: u.id, name: u.name })); // yeniden şekillendirme (map) // Göndermeden önce changeable veriyi izole etmek gerekirse: const payload = JSON.parse(JSON.stringify(filtered));
Bu akışta filter ile önce gerekli kayıtları seçer, sonra map ile ağ için hafif bir yapı oluşturursunuz. Payload üzerinde değişiklik gerekiyorsa JSON derin kopyası ile orijinali koruyabilirsiniz; ancak büyük verilerde performansı değerlendirin.
8) Performans ve iyi uygulamalar
- Map/filter gibi fonksiyonel yöntemler genellikle daha okunabilir ve yan etki (side-effect) içermez; büyük veri setlerinde zincirleme kullanımda ara yapı sayısını azaltmak için tek döngüyle çözüm düşünün.
- Derin kopyalama maliyetli olabilir. Sık sık büyük nesneleri kopyalamadan önce gerçekten gerekli olup olmadığını kontrol edin.
- Object.assign hedef nesneyi değiştirdiği için yeni bir boş nesneyle çağırarak ({}) orijinali koruyun.
9) Yaygın hatalar ve dikkat noktaları
- map() içinde dönüş değeri (return) unutulursa, yeni dizi undefined içerir. Her iterasyonda dönüş değeri olduğundan emin olun.
- filter() içinde boolean döndürün; koşul hataları istenmeyen sonuçlar verir.
- JSON.parse(JSON.stringify()) yönteminin bazı veri türlerini farklı şekilde ele alabileceğini unutmayın; kritik veri tipleriniz varsa test edin.
Sıkça Sorulan Sorular
S1: map ile forEach arasındaki fark nedir?
map yeni bir dizi döndürür; forEach sadece her eleman üzerinde yan etki amaçlı işlem yapar ve dönüş değeri yoktur. Yeni bir dizi istiyorsanız map tercih edilir. Kaynak: MDN map.
S2: Object.assign derin kopya mı yapar?
Hayır. Object.assign yüzeysel (shallow) kopya/merge yapar; iç içe nesneler referans olarak paylaşılır. Derin kopya gerekiyorsa farklı yöntemlere bakın. Kaynak: Coddy.
S3: JSON.parse(JSON.stringify()) her zaman güvenli mi?
Bu yöntem JSON olarak serileştirilebilen yapılar için işe yarar ancak bazı özel tiplerde bilgi kaybı veya farklı davranış olabilir. Kritik durumlarda özel derin kopyalama kütüphanesi veya uygun seri/parse stratejisi kullanın.
Anahtar Çıkarımlar
- map() her elemanı dönüştürerek yeni bir dizi üretir (MDN referansı).
- filter() koşulu sağlayan elemanlardan yeni bir dizi döndürür (MDN referansı).
- slice() dizinin bir parçasının yüzeysel kopyasını alır (MDN referansı).
- Object.assign() nesneleri birleştirir ama yüzeysel kopya yapar (pratik rehberler).
- JSON.parse(JSON.stringify()) JSON-uyumlu yapılar için pratik bir derin kopya yöntemidir; bazı türlerde sınırlamalar olabilir (Coddy rehberi).
Bu rehberdeki örnekler günlük kodda hızlıca uygulanabilir. Daha karmaşık senaryolarda, kullandığınız veri tiplerinin özelliklerini test ederek ve performansı ölçerek uygun yöntemi seçin.