Symbol, her çağrıda benzersiz bir değer üreten ilkel (primitive) bir tiptir. Symbol("id") === Symbol("id") her zaman false döner. Symbol'ler genellikle başka kodun eklediği anahtarlarla çakışmayacak, for...in, Object.keys ve JSON.stringify tarafından görülmeyen özellik anahtarları oluşturmak için kullanılır. Ayrıca Symbol.iterator ve Symbol.toPrimitive gibi "well-known" symbol'ler, dilin yerleşik davranışlarını kendi nesnelerinize uyarlamanızı sağlar.

Bu yazıda symbol oluşturmayı, symbol anahtarlı özelliklerin nerede göründüğünü ve nerede gizlendiğini, Symbol.for ile global kayıt defterini ve en çok kullanılan well-known symbol'leri çalışan örneklerle görüyorsunuz. Diğer ilkel tiplerle karşılaştırma için veri tipleri yazısına bakabilirsiniz.

Symbol oluşturmak

Symbol() fonksiyonu isteğe bağlı bir açıklama metni alır. Bu açıklama yalnızca hata ayıklama içindir; symbol'e açıklama üzerinden ulaşamazsınız. description özelliği açıklamayı, toString() ise Symbol(...) biçimindeki metni verir. new Symbol() yazmak hata verir.

javascript
const a = Symbol("kimlik");
const b = Symbol("kimlik");
console.log(a === b); // false
console.log(typeof a); // symbol
console.log(a.toString(), a.description); // Symbol(kimlik) kimlik
console.log(Symbol().description); // undefined

new Symbol();
// TypeError: Symbol is not a constructor

a + "";
// TypeError: Cannot convert a Symbol value to a string
console.log(String(a)); // Symbol(kimlik)

Symbol'ler metne kendiliğinden çevrilmez. Bu, bir symbol'ü yanlışlıkla metin anahtarına dönüştürmenizi engeller. Açıkça metin istiyorsanız String(sym) ya da sym.description kullanın.

Tip dönüşüm kuralları

Symbol, dönüşüm konusunda diğer ilkel tiplerden daha katıdır. MDN'nin listelediği kurallar Node.js 24 ile şöyle görünür:

javascript
const sym = Symbol("x");
+sym;
// TypeError: Cannot convert a Symbol value to a number
`${sym}`;
// TypeError: Cannot convert a Symbol value to a string
new String(sym);
// TypeError: Cannot convert a Symbol value to a string
console.log(Object(sym) == sym); // true
console.log(String(sym)); // Symbol(x)

Kısacası sayıya çevirme her zaman hata verir; metne çevirme yalnızca String() fonksiyonu ile açıkça yapılabilir. Şablon metin içinde symbol kullanacaksanız description özelliğini yazın. Tip dönüşümünün genel mantığı tip dönüşümü yazısında anlatılıyor.

Symbol anahtarlı özellikler

Symbol anahtarlı özellikler: for...in, Object.keys / Object.entries, JSON.stringify, Object.getOwnPropertySymbols

Bir symbol'ü hesaplanmış özellik adı olarak ([ID]) kullanabilirsiniz. Bu özellik metin anahtarlarını listeleyen mekanizmalarda görünmez; yine de gerçek anlamda gizli değildir, Object.getOwnPropertySymbols veya Reflect.ownKeys ile bulunabilir. MDN bunu zayıf bir kapsülleme olarak tanımlar. Gerçek gizlilik için sınıfların #özel alanlarını kullanın.

javascript
const ID = Symbol("id");
const urun = { ad: "Klavye", fiyat: 750, [ID]: 9001 };

console.log(urun[ID]); // 9001
console.log(Object.keys(urun)); // [ 'ad', 'fiyat' ]
for (const k in urun) console.log(k); // ad, fiyat
console.log(JSON.stringify(urun)); // {"ad":"Klavye","fiyat":750}
console.log(Object.getOwnPropertySymbols(urun)); // [ Symbol(id) ]
console.log(Reflect.ownKeys(urun)); // [ 'ad', 'fiyat', Symbol(id) ]
console.log({ ...urun }[ID]); // 9001

Bu davranışın pratik bir kullanımı, başkasının oluşturduğu nesneye çakışma riski olmadan işaret koymaktır. Aşağıdaki fonksiyon bir kaydın işlenip işlenmediğini symbol ile işaretler; işaret JSON çıktısına sızmaz ve nesnede aynı adlı bir metin alanı olsa bile onunla karışmaz:

javascript
const ISLENDI = Symbol("islendi");
function isle(kayit) {
  if (kayit[ISLENDI]) return "zaten işlendi";
  kayit[ISLENDI] = true;
  return "işlendi";
}
const k = { id: 7 };
console.log(isle(k)); // işlendi
console.log(isle(k)); // zaten işlendi
console.log(JSON.stringify(k)); // {"id":7}
MekanizmaSymbol anahtarı görünür mü?
for...inHayır
Object.keys / Object.entriesHayır
JSON.stringifyHayır, tamamen atlanır
Object.getOwnPropertySymbolsEvet
Reflect.ownKeysEvet
Spread ve Object.assignEvet, kopyalanır

Global kayıt defteri: Symbol.for ve Symbol.keyFor

Symbol() her seferinde yeni bir değer üretir. Farklı dosyalar, hatta farklı realm'ler (örneğin iframe) arasında aynı symbol'ü paylaşmak istiyorsanız Symbol.for(anahtar) kullanın: anahtar kayıtlıysa mevcut symbol'ü, değilse yeni oluşturup kaydettiği symbol'ü döndürür. Symbol.keyFor tersini yapar ve kayıtlı olmayan symbol'ler için undefined döner.

javascript
const s1 = Symbol.for("uygulama.oturum");
const s2 = Symbol.for("uygulama.oturum");
console.log(s1 === s2); // true
console.log(Symbol.keyFor(s1)); // uygulama.oturum
console.log(Symbol.keyFor(Symbol("yerel"))); // undefined
console.log(Symbol.keyFor(Symbol.iterator)); // undefined

Symbol.keyFor("metin");
// TypeError: metin is not a symbol

Kayıt defteri adları global olduğu için başka kütüphanelerle çakışmamak adına "uygulama.oturum" gibi ön ekli, açıklayıcı anahtarlar seçmek iyi bir alışkanlıktır. Kayıt defterinin içeriğini listelemenin bir yolu yoktur; ona yalnızca for() ve keyFor() üzerinden erişilir.

Well-known symbol'ler

Well-known symbol'ler: Symbol.iterator: nesneyi döngüye uygun hale getirmek, Symbol.toPrimitive: dönüşümü kontrol etmek, Symbol.toStringTag ve Symbol.hasInstance

Symbol kurucusunun statik özellikleri, dilin yerleşik işlemlerinin baktığı "protokol" anahtarlarıdır. Bir nesneye bu anahtarlarla metot eklediğinizde ilgili dil özelliği sizin metodunuzu kullanır. Bunlar global kayıt defterinde değildir, bu yüzden Symbol.keyFor(Symbol.iterator) undefined döner.

SymbolKullanan dil özelliği
Symbol.iteratorfor...of, spread, dizi destructuring
Symbol.asyncIteratorfor await...of
Symbol.toPrimitiveNesneyi ilkel değere çevirme (+obj, şablon metin, ==)
Symbol.toStringTagObject.prototype.toString çıktısı
Symbol.hasInstanceinstanceof
Symbol.dispose / Symbol.asyncDisposeusing / await using bildirimleri
Symbol.isConcatSpreadableArray.prototype.concat

Symbol.iterator: nesneyi döngüye uygun hale getirmek

for...of bir nesneyi dolaşmadan önce onun [Symbol.iterator]() metodunu çağırır. Düz nesnelerde bu metot olmadığı için döngü hata verir. Generator metodu ile bu protokolü birkaç satırda uygulayabilirsiniz; ayrıntı generator ve iterator yazısında.

javascript
class Aralik {
  constructor(bas, son, adim = 1) {
    this.bas = bas;
    this.son = son;
    this.adim = adim;
  }
  *[Symbol.iterator]() {
    for (let i = this.bas; i <= this.son; i += this.adim) yield i;
  }
}
console.log([...new Aralik(1, 10, 3)]); // [ 1, 4, 7, 10 ]
const [ilk, ikinci] = new Aralik(5, 9);
console.log(ilk, ikinci); // 5 6

for (const x of { a: 1 }) {}
// TypeError: {(intermediate value)} is not iterable

Symbol.toPrimitive: dönüşümü kontrol etmek

Bir nesne sayıya, metne ya da ilkel değere çevrilirken motor önce [Symbol.toPrimitive](hint) metodunu arar. hint değeri "number", "string" ya da "default" olur. Metot ilkel bir değer döndürmek zorundadır; nesne döndürürse TypeError fırlatılır. Bu metot yoksa valueOf() ve toString() kullanılır.

javascript
class Para {
  constructor(kurus) { this.kurus = kurus; }
  [Symbol.toPrimitive](ipucu) {
    if (ipucu === "string") return `${(this.kurus / 100).toFixed(2)} TL`;
    return this.kurus / 100; // "number" ve "default"
  }
}
const p = new Para(1250);
console.log(+p); // 12.5
console.log(`${p}`); // 12.50 TL
console.log(p + 1); // 13.5
console.log(p > 10); // true

Symbol.toStringTag ve Symbol.hasInstance

javascript
class Dogrulayici {
  get [Symbol.toStringTag]() { return "Dogrulayici"; }
}
console.log(Object.prototype.toString.call(new Dogrulayici())); // [object Dogrulayici]
console.log(Object.prototype.toString.call(new Map())); // [object Map]

class Cift {
  static [Symbol.hasInstance](n) { return Number.isInteger(n) && n % 2 === 0; }
}
console.log(4 instanceof Cift, 3 instanceof Cift); // true false

Symbol.hasInstance ile instanceof davranışını değiştirmek mümkündür, ama okuyan kişiyi şaşırtabilir; gerçek kodda bir doğrulama fonksiyonu genellikle daha anlaşılırdır.

Sık yapılan hatalar

  • Symbol anahtarlı veriyi JSON.stringify ile kaydetmeye çalışmak: bu özellikler sessizce atlanır.
  • Symbol'ü gizlilik mekanizması sanmak: Reflect.ownKeys ile görülebilir; gerçek gizlilik için # alanları kullanın.
  • Modüller arasında paylaşılması gereken bir anahtar için Symbol() kullanmak: her modül farklı bir değer üretir; ortak anahtar gerekiyorsa symbol'ü dışa aktarın ya da Symbol.for kullanın.
  • Symbol'ü + ile metne eklemek: TypeError verir; description kullanın.

Sık Sorulan Sorular

Symbol ne zaman kullanılmalı?

Başkasının nesnesine çakışma riski olmadan meta veri eklemek, kütüphaneler arasında ortak bir protokol tanımlamak ve for...of gibi dil özelliklerini kendi nesnelerinize uyarlamak için uygundur. Günlük veri modelleri için metin anahtarlar yeterlidir.

Symbol.for ile Symbol() arasındaki fark nedir?

Symbol() her çağrıda yeni ve benzersiz bir değer üretir. Symbol.for("x") aynı anahtar için her yerde aynı değeri döndürür, ama bu yüzden toplanamaz ve zayıf koleksiyonlarda kullanılamaz.

Symbol bir WeakMap anahtarı olabilir mi?

Symbol("x") ile oluşturulan kayıtsız symbol'ler toplanabildiği için olabilir. Symbol.for ile oluşturulan kayıtlı symbol'ler ise reddedilir; Node.js 24 bu durumda TypeError: Invalid value used as weak map key verir.

Symbol anahtarlı özellikler kopyalanır mı?

Evet. Spread sözdizimi ve Object.assign kendi, numaralandırılabilir symbol özelliklerini de kopyalar. Yalnızca JSON.stringify, for...in ve Object.keys bunları atlar.

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 · Generator ve iterator · Veri tipleri · Tip dönüşümü · Proxy ve Reflect