Map, anahtarı herhangi bir değer olabilen ve ekleme sırasını koruyan bir anahtar-değer koleksiyonudur. Set her değeri yalnızca bir kez tutan bir değer koleksiyonudur. WeakMap ve WeakSet bunların "zayıf" sürümleridir: anahtar olarak yalnızca nesne (ve kayıtsız Symbol) kabul eder, bu anahtarları çöp toplayıcıdan (garbage collector) korumaz ve içerikleri gezilemez.

Kısa cevap: anahtarlar baştan bilinen sabit alanlarsa (bir kullanıcının adı, e-postası gibi) düz nesne; anahtarlar çalışma anında ekleniyor, siliniyor, metin dışı türde oluyor ya da kullanıcıdan geliyorsa Map kullanın. Tekrarsız liste için Set, bir nesneye onun ömrüne bağlı ek veri iliştirmek için WeakMap doğru araçtır. Bu yazıda dördünü örneklerle karşılaştırıyoruz. Genel yol haritası JavaScript öğrenme rehberinde.

Map temelleri

Map temelleri

Bir Map'e set(anahtar, değer) ile ekler, get() ile okur, has() ile varlığını sorar, delete() ile silersiniz. Eleman sayısı size özelliğindedir. set() Map'in kendisini döndürdüğü için çağrılar zincirlenebilir.

javascript
const stok = new Map();
stok.set("kalem", 120).set("defter", 40);

console.log(stok.get("kalem")); // 120
console.log(stok.has("silgi")); // false
console.log(stok.get("silgi")); // undefined
console.log(stok.size); // 2

stok.delete("defter");
console.log(stok); // Map(1) { 'kalem' => 120 }

// Ekleme sırasıyla gezilir; her adım [anahtar, değer] çiftidir
const fiyat = new Map([["elma", 40], ["muz", 65]]);
for (const [urun, tl] of fiyat) {
  console.log(urun, tl);
}
// elma 40
// muz 65

Map yalnızca anahtarları ya da yalnızca değerleri gezmek için keys() ve values(), çiftler için entries() metotlarını sunar. Bunlar dizi değil iterator döndürür; dizi gerekiyorsa spread ile açın. forEach() de vardır, ancak callback fonksiyonun argüman sırası (değer, anahtar) biçimindedir; ters yazmak yaygın bir hatadır.

javascript
const m2 = new Map([["x", 1], ["y", 2]]);
console.log([...m2.keys()], [...m2.values()]); // [ 'x', 'y' ] [ 1, 2 ]
m2.forEach((deger, anahtar) => console.log(anahtar, deger));
// x 1
// y 2

Çıktıdaki => işareti Node.js'in Map'i yazdırma biçimidir, bir arrow function değildir. Döngüdeki [urun, tl] yazımı için destructuring yazısına bakabilirsiniz.

Map anahtarı olarak nesne ve NaN

Düz nesnede anahtarlar metne (ya da Symbol'e) çevrilir. Map ise anahtarın türünü korur: sayı, nesne, fonksiyon her şey anahtar olabilir. Anahtar karşılaştırması MDN'nin "SameValueZero" dediği kurala göre yapılır; pratikte === gibidir ama NaN kendine eşit sayılır. Nesne anahtarları referansa göre karşılaştırılır, içeriğe göre değil.

javascript
const m = new Map();
const kullanici = { id: 1 };

m.set(kullanici, "oturum-a");
m.set(1, "sayı bir");
m.set("1", "metin bir");
m.set(NaN, "sayı değil");

console.log(m.get(kullanici)); // oturum-a
console.log(m.get({ id: 1 })); // undefined (farklı nesne)
console.log(m.get(1), "/", m.get("1")); // sayı bir / metin bir
console.log(m.get(NaN)); // sayı değil

const nesne = {};
nesne[1] = "a";
nesne["1"] = "b";
console.log(nesne); // { '1': 'b' }

Map mi düz nesne mi?

Map mi düz nesne mi? Anahtar türü, Varsayılan anahtarlar, Kullanıcı girdisi anahtar, Sıra

MDN, Map ile düz nesneyi birkaç başlıkta karşılaştırır. Özet:

KonuMapDüz nesne
Anahtar türüher değer (nesne, fonksiyon, sayı...)yalnızca string ve Symbol
Varsayılan anahtarlaryok, sadece eklediğinizprototipten gelenlerle çakışabilir
Kullanıcı girdisi anahtargüvenliprototype pollution riski (null prototip ile azaltılır)
Sıraekleme sırasıkuralları karmaşık, güvenmeyin
Eleman sayısısize özelliğiObject.keys(obj).length
Gezinmedoğrudan for...ofObject.entries ile
Sık ekleme/silmebu senaryoda daha iyi performansbu senaryo için optimize değil
JSON desteğiyerleşik yokJSON.stringify ve JSON.parse ile doğrudan

İkisi arasında dönüşüm kolaydır: new Map(Object.entries(obj)) nesneden Map, Object.fromEntries(map) Map'ten nesne üretir (bkz. Object metotları). Map doğrudan JSON'a yazılamaz; JSON.stringify(new Map([["a", 1]])) sonucu "{}" olur. Çözüm yolları JSON.parse ve JSON.stringify yazısında.

Set: tekrarsız değerler

Set'e add() ile değer eklersiniz; aynı değer ikinci kez eklenmez. Değer kontrolü Map'teki anahtar kuralıyla aynıdır. MDN, has() metodunun ortalamada, aynı uzunluktaki bir dizide includes() çağırmaktan daha hızlı olduğunu belirtir. Dizideki tekrarları silmenin en kısa yolu da Set'tir:

javascript
const etiketler = ["js", "node", "js", "react", "node"];
const tekil = [...new Set(etiketler)];
console.log(tekil); // [ 'js', 'node', 'react' ]

const goruldu = new Set();
goruldu.add(5).add(5).add("5");
console.log(goruldu.size); // 2
console.log(goruldu.has(5)); // true

// Metindeki farklı harfler
console.log(new Set("merhaba").size); // 6

Set kompozisyon metotları: union, intersection ve diğerleri

Set'e matematikteki küme işlemlerini yapan yeni metotlar eklendi. union(), intersection(), difference() ve symmetricDifference() yeni bir Set döndürür; isSubsetOf(), isSupersetOf() ve isDisjointFrom() ise true/false döndürür. Bu metotlar görece yenidir; örnekler Node.js 24 ile çalıştı, hedef ortamlarınız için MDN uyumluluk tablosuna bakın.

javascript
const frontend = new Set(["js", "css", "html"]);
const backend = new Set(["js", "sql", "linux"]);

console.log(frontend.union(backend)); // Set(5) { 'js', 'css', 'html', 'sql', 'linux' }
console.log(frontend.intersection(backend)); // Set(1) { 'js' }
console.log(frontend.difference(backend)); // Set(2) { 'css', 'html' }
console.log(frontend.symmetricDifference(backend)); // Set(4) { 'css', 'html', 'sql', 'linux' }
console.log(new Set(["js"]).isSubsetOf(frontend)); // true
console.log(frontend.isDisjointFrom(new Set(["go"]))); // true

Argümanın gerçek bir Set olması gerekmez; MDN'nin "set-like" dediği, size özelliği ile has() ve keys() metotları olan her nesne kabul edilir. Map bu koşulu sağladığı için anahtarlarıyla birlikte kullanılabilir. Diziler ise has() ve size içermediğinden doğrudan verilemez; önce new Set(dizi) ile çevirin.

WeakMap: nesneye ömrü kadar veri iliştirmek

WeakMap'in anahtarları nesne ya da kayıtsız (registered olmayan) Symbol olmalıdır. Bir nesnenin WeakMap'te anahtar olması onu çöp toplamadan korumaz; nesneye başka hiçbir yerden ulaşılamıyorsa nesne ve ona bağlı değer toplanabilir. Bu yüzden WeakMap'in size özelliği, keys() veya forEach() gibi gezinme metotları yoktur; MDN bunu, liste vermenin çöp toplamanın anlık durumuna bağımlı, öngörülemez bir sonuç üreteceğiyle açıklar. Yalnızca set, get, has ve delete vardır.

javascript
const hesapOnbellegi = new WeakMap();

function ozet(nesne) {
  if (hesapOnbellegi.has(nesne)) return hesapOnbellegi.get(nesne);
  const sonuc = Object.values(nesne).reduce((a, b) => a + b, 0);
  hesapOnbellegi.set(nesne, sonuc);
  return sonuc;
}

const sepet = { kitap: 120, kalem: 15 };
console.log(ozet(sepet)); // 135
console.log(hesapOnbellegi.has(sepet)); // true

try {
  hesapOnbellegi.set("metin", 1);
} catch (e) {
  console.log(e.name); // TypeError
}

Bu kalıp, fonksiyona verilen nesneyle sonucunu ilişkilendirip aynı nesne tekrar geldiğinde hesaplamayı atlamak için kullanılır. MDN'nin uyarısı: anahtar nesne yaşadığı sürece sonuç da bellekte kalır. Çöp toplamanın ayrıntıları için bellek yönetimi yazısına, sınıflarda özel alan yerine WeakMap kullanımı ve # alanları için class yazısına bakabilirsiniz.

WeakSet: nesneleri işaretlemek

WeakSet de yalnızca nesne ve kayıtsız Symbol tutar, gezilemez ve size özelliği yoktur. Tipik kullanımı "bu nesneyi daha önce gördüm mü?" sorusudur; örneğin iç içe bir yapıyı gezerken döngüsel referansa takılmamak:

javascript
function derinlikSay(nesne, gorulen = new WeakSet()) {
  if (typeof nesne !== "object" || nesne === null) return 0;
  if (gorulen.has(nesne)) return 0; // döngü
  gorulen.add(nesne);
  let enDerin = 0;
  for (const deger of Object.values(nesne)) {
    enDerin = Math.max(enDerin, derinlikSay(deger, gorulen));
  }
  return enDerin + 1;
}

const a = { b: { c: {} } };
a.b.c.geri = a; // döngüsel referans
console.log(derinlikSay(a)); // 3

Dört koleksiyonun özeti

YapıNe tutarAnahtar/değer türüGezilebilir misize
Mapanahtar-değerher türevet, ekleme sırasıylavar
Settekil değerher türevet, ekleme sırasıylavar
WeakMapanahtar-değeranahtar: nesne veya kayıtsız Symbolhayıryok
WeakSettekil değernesne veya kayıtsız Symbolhayıryok

Sık yapılan hatalar

Sık yapılan hatalar: Nesne anahtarı içeriğe göre aramak, Map'e köşeli parantezle yazmak, WeakMap'i listelemeye çalışmak, Set'te nesneleri tekilleştirmeyi beklemek
  • Nesne anahtarı içeriğe göre aramak: m.get({ id: 1 }) her zaman yeni bir nesne oluşturur ve eşleşmez. Anahtarın aynı referansını saklayın ya da metin bir kimlik (id) kullanın.
  • Map'e köşeli parantezle yazmak: Veri Map'e değil nesneye eklenir; set() kullanın.
  • WeakMap'i listelemeye çalışmak: İçeriği gezmeniz gerekiyorsa Map kullanın.
  • Set'te nesneleri tekilleştirmeyi beklemek: İçeriği aynı iki ayrı nesne, farklı referans oldukları için Set'te iki ayrı öğedir.

Sık Sorulan Sorular

Object.groupBy yerine Map.groupBy ne zaman kullanılır?

Object.groupBy() grup anahtarlarını metne çevirir. Gruplar bir nesneyle temsil ediliyorsa ve o nesneyi anahtar olarak kullanmak istiyorsanız Map.groupBy() bir Map döndürür. MDN, anahtar sabit bir değerse metin kullanıp Object.groupBy() tercih edilebileceğini belirtir.

Map'te "yoksa ekle" işlemi için kısa bir yol var mı?

Klasik yol if (!m.has(k)) m.set(k, v) biçimidir. MDN'de Map.prototype.getOrInsert() ve getOrInsertComputed() metotları da belgelenmiştir; ancak bu metotlar çok yenidir ve bu yazıyı denediğimiz Node.js 24.4 sürümünde tanımlı değildi. Kullanmadan önce MDN uyumluluk tablosuna bakın.

Set elemanlarına indeksle erişebilir miyim?

Hayır, Set'in indeksi yoktur. Sıralı erişim gerekiyorsa [...set] ile diziye çevirip dizi metotlarını kullanın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: JavaScript öğrenme rehberi · Object metotları · Bellek yönetimi ve garbage collection · Symbol nedir · JSON.parse ve JSON.stringify