Mert Özen Her Satırda Daha İleri
Frontend JavaScript Temel — #12

JavaScript Object'leri: Object Literal, Property, Object.keys ve structuredClone

Mert Özen 3 Kas 2026 8 dk 3 görüntülenme
JavaScript Object'leri: Object Literal, Property, Object.keys ve structuredClone

Object literal'i, nokta ve köşeli parantezle property erişimini, iç içe object'leri, method ve this'i, in ile Object.keys/values/entries'i, for...in'i, spread ile sığ, structuredClone ile derin kopyayı öğ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

Array'ler yazısında spread ile kopya almanın "sığ" olduğunu söylemiş ve konuyu object'lere bırakmıştık. Sıra geldi. Şu koda bak:

const user = { name: "Ada", address: { city: "Izmir" } };
const copy = { ...user };

copy.name = "Grace";
copy.address.city = "Ankara";

console.log(user.name, user.address.city);

Kopyayı değiştirdik. Peki orijinal user bundan etkilendi mi? Konsolda Ada Izmir mı, Grace Ankara mı, yoksa ikisinin karışımı bir şey mi çıkar? Okumaya devam etmeden önce bir tahmin yap. Cevabı kopyalama bölümünde açıklayacağız.

Object Literal: İlişkili Veriyi Bir Arada Tutmak

Bir kullanıcının adını, yaşını ve e-postasını ayrı ayrı değişkenlerde tutabilirsin, ama bir süre sonra hangi değişkenin hangi kullanıcıya ait olduğunu takip edemezsin. Object, birbiriyle ilişkili verileri tek bir çatı altında toplar. Onu üzerinde etiketli çekmeceleri olan bir dosya dolabı gibi düşün: her çekmecenin bir adı (key) ve içinde bir değeri (value) var. Bunu tarayıcının konsoluna yapıştırıp dene:

const user = {
  name: "Ada",
  age: 28,
  email: "ada@example.com",
  isAdmin: false,
  skills: ["HTML", "CSS", "JavaScript"]
};

console.log(user);
console.log(typeof user); // "object"

Süslü parantezlerle yazılan bu yapıya object literal denir. Her satır bir property: solda key, iki nokta, sağda value. Property'ler virgülle ayrılır. Value her şey olabilir: string, sayı, boolean, array, hatta başka bir object ya da fonksiyon. Key'ler ise aslında birer string'dir; tırnak koymadan yazabiliyorsan bu yalnızca bir kolaylık.

Property Okumak ve Yazmak

Bir property'ye ulaşmanın iki yolu var: nokta ve köşeli parantez.

const user = { name: "Ada", age: 28 };

console.log(user.name);    // "Ada"
console.log(user["age"]);  // 28
console.log(user.phone);   // undefined

user.age = 29;             // güncelle
user.city = "Izmir";       // yeni property ekle
delete user.city;          // property'yi sil
console.log(user);         // { name: "Ada", age: 29 }

Olmayan bir property'yi okuduğunda hata almazsın, undefined gelir. Var olan bir property'ye değer atarsan güncellenir, olmayana atarsan yeni bir çekmece açılır. delete ise çekmeceyi tamamen söker.

Nokta yazımı kısa ve okunur, günlük kodda çoğunlukla onu kullanırsın. Köşeli parantez iki durumda şart. Birincisi, key boşluk ya da tire gibi karakterler içeriyorsa. İkincisi ve daha önemlisi, key'in adı bir değişkende duruyorsa:

const product = { "product name": "Keyboard", price: 750 };
console.log(product["product name"]); // "Keyboard"

const field = "price";
console.log(product[field]); // 750
console.log(product.field);  // undefined

Son satır sık yapılan bir hata. product.field, "field" adında bir property arar. product[field] ise önce field değişkeninin değerine bakar, yani "price"'a, ve o çekmeceyi açar. Hangi property'yi okuyacağın kod çalışırken belli oluyorsa köşeli parantez kullanırsın.

İç İçe Object'ler ve Object Array'leri

Bir object'in içinde başka bir object, bir array'in içinde de object'ler olabilir. Gerçek dünyadaki verilerin çoğu tam olarak böyle görünür:

const order = {
  id: 1024,
  customer: {
    name: "Grace",
    address: { city: "Bursa", zip: "16000" }
  },
  items: [
    { title: "Pen", price: 25 },
    { title: "Notebook", price: 60 }
  ]
};

console.log(order.customer.name);         // "Grace"
console.log(order.customer.address.city); // "Bursa"
console.log(order.items[1].title);        // "Notebook"
console.log(order.items.length);          // 2

Okumak için yolu adım adım takip edersin: önce order, oradan customer, oradan address, en son city. Array'e gelince index ile bir element seçer, sonra yine noktayla devam edersin. Daha önce gördüğümüz döngüler ve forEach da bu yapılarla çok iyi anlaşır; bir siparişin toplamını hesaplamak items üzerinde bir tur dönmekten ibaret.

Method ve this'e İlk Dokunuş

Bir property'nin değeri fonksiyon olduğunda ona method deriz. console.log'daki log da, string'lerdeki toUpperCase da birer method. Kendi object'imize de method ekleyebiliriz:

const counter = {
  count: 0,
  increase: function () {
    this.count = this.count + 1;
    return this.count;
  }
};

console.log(counter.increase()); // 1
console.log(counter.increase()); // 2
console.log(counter.count);      // 2

Method'un içindeki this, o an method'u çağıran object'i gösterir. counter.increase() yazdığında noktanın solunda counter var, dolayısıyla this da counter. Kendi çekmecelerine "benim" diye işaret etmenin yolu bu. Method yazmanın daha kısa bir syntax de var, onu Orta seride modern syntax'ıyla birlikte göreceğiz. this'in nasıl belirlendiği ve arrow function'larda neden farklı davrandığı ise kendi başına bir konu; onu da Orta seride detaylandıracağız.

Property Var mı? in ve Object.keys/values/entries

Bir object'te belli bir property olup olmadığını in operatörüyle sorarsın:

const settings = { theme: "dark", fontSize: 16, sidebar: undefined };

console.log("theme" in settings);           // true
console.log("language" in settings);        // false
console.log("sidebar" in settings);         // true
console.log(settings.sidebar !== undefined); // false

Son iki satıra dikkat. sidebar çekmecesi var ama içi boş, değeri undefined. in çekmecenin varlığına bakar ve true der. undefined ile karşılaştırmak ise içeriğe bakar ve yanıltabilir.

Object'in bütün key'lerini, value'larını ya da ikisini birden bir array olarak almak için üç yardımcı var. Object.keys eskiden beri dilde; Object.values ve Object.entries ES2017 ile geldi:

const scores = { alan: 85, ada: 92, grace: 78 };

console.log(Object.keys(scores));   // ["alan", "ada", "grace"]
console.log(Object.values(scores)); // [85, 92, 78]
console.log(Object.entries(scores));
// [["alan", 85], ["ada", 92], ["grace", 78]]

console.log(Object.keys(scores).length); // 3

Bunların güzelliği, sonucun bir array olması. Artık array'ler için öğrendiğin her şeyi kullanabilirsin: length ile property sayısını bulmak, includes ile arama yapmak, for...of ya da forEach ile gezmek. Object.entries'in her element'i iki element'li bir array: ilki key, ikincisi value.

for...in ile Object'i Gezmek

Daha önce döngüler yazısında for...in'in object'ler için olduğunu söylemiştik. Her turda sıradaki key'i verir:

const scores = { alan: 85, ada: 92, grace: 78 };

for (const key in scores) {
  console.log(`${key}: ${scores[key]}`);
}
// alan: 85
// ada: 92
// grace: 78

for (const entry of Object.entries(scores)) {
  console.log(entry[0], entry[1]);
}

Döngünün içinde value'ya ulaşmak için köşeli parantez kullandık, çünkü key bir değişkende duruyor; az önceki kuralın tam kendisi. for...in, object'in kendi property'lerinin yanında miras aldığı property'leri de gezebilir; prototype konusunu İleri seride göreceğiz. Bu yüzden birçok ekip, ikinci örnekteki gibi Object.entries ile for...of ikilisini tercih eder. entry[0] ve entry[1] yazmak biraz hantal duruyorsa haklısın; destructuring ile bunu çok daha şık yazmayı Orta seride göreceğiz.

Object Kopyalamak: Spread ve structuredClone

Baştaki sorunun cevabı: Ada Ankara. İsim korundu, şehir değişti.

ES2018 ile gelen object spread'i { ...user }, yeni bir object oluşturur ve user'ın property'lerini tek tek bu yeni object'e kopyalar. name bir string, yani bir değer; kopyaya değerin kendisi geçer. Bu yüzden copy.name'i değiştirmek orijinali etkilemedi. Ama address bir object ve kopyaya geçen şey object'in kendisi değil, ona giden referans. Yeni dosya dolabının address çekmecesinde, eski dolaptakiyle aynı odanın anahtarı duruyor. copy.address.city'yi değiştirdiğinde o ortak odadaki eşyayı değiştirmiş oldun. Buna sığ kopya (shallow copy) denir: yalnızca ilk katman kopyalanır.

İç içe object'leri de bağımsız kopyalamak, yani derin kopya (deep copy) almak için tarayıcıda structuredClone var:

const user = { name: "Ada", address: { city: "Izmir" } };
const deep = structuredClone(user);

deep.address.city = "Ankara";
console.log(user.address.city); // "Izmir"
console.log(deep.address.city); // "Ankara"

Küçük bir ayrıntı: structuredClone ECMAScript'in değil, web platformunun bir parçası. Yani dilin kendisinden değil, tarayıcının sunduğu API'lerden geliyor; 2022'den beri bütün büyük tarayıcılarda var. Date, Map, Set gibi yerleşik tipleri ve kendine referans veren object'leri doğru kopyalar. Sınırları da var:

const withMethod = { name: "Ada", greet: function () { return "Hello"; } };

try {
  structuredClone(withMethod);
} catch (error) {
  console.log(error.name); // "DataCloneError"
}

Fonksiyon içeren bir object'i kopyalayamaz ve hata fırlatır. DOM element'lerini de kopyalayamaz. Class'larla oluşturulmuş object'leri kopyalarken de class bilgisini kaybeder ve düz bir object döner; class'ları Orta seride göreceğiz. Düz veriden oluşan object'ler için ise derin kopyanın en temiz yolu bu. Bir sonraki yazıda JSON ile kopyalama yöntemini de göreceğiz ve neden structuredClone'un daha iyi bir seçim olduğunu konuşacağız.

Sık Düşülen Tuzaklar

Atama kopyalamaz, === içeriğe bakmaz

const original = { score: 10 };
const alias = original;
alias.score = 99;

console.log(original.score);        // 99
console.log(alias === original);    // true
console.log({ a: 1 } === { a: 1 }); // false

Array'lerdeki kuralın aynısı. alias = original yeni bir object oluşturmaz, aynı object'e ikinci bir isim verir. === ise iki object'in içeriğini değil, aynı object olup olmadıklarını karşılaştırır. İçerikleri birebir aynı iki ayrı object literal'i bu yüzden eşit sayılmaz.

const object'i dondurmaz

const user = {...} yazdığında user'a başka bir object atayamazsın, ama içindeki property'leri değiştirebilir, ekleyip silebilirsin. Daha önce değişkenler yazısında gördüğümüz yeniden atama ile mutasyon farkı burada da geçerli. Object'i gerçekten değiştirilemez yapmanın yollarını İleri seride göreceğiz.

Olmayan bir object'in içine bakmak

const user = { name: "Ada" };
console.log(user.address);  // undefined

try {
  console.log(user.address.city);
} catch (error) {
  console.log(error.name);  // "TypeError"
}

Olmayan bir property'yi okumak undefined verir, sorun yok. Ama undefined'ın içinde bir şey aramaya kalkarsan TypeError alırsın. Sunucudan gelen eksik verilerde sık yaşanır. Önce bir if ile kontrol edebilirsin; bunu tek satırda güvenle yapan ?. operatörünü Orta seride göreceğiz.

Küçük Bir Deneme

★☆☆ Kendini anlatan bir me object'i oluştur: ad, şehir, doğum yılı ve en sevdiğin üç programlama konusundan oluşan bir array. Sonra bir job property'si ekle, doğum yılını sil ve her adımda object'i konsola yazdır.

★★☆ Çalıştırmadan önce tahmin et: const a = { x: 1, y: { z: 2 } }; ve const b = { ...a }; için b.x = 5; b.y.z = 9; çalıştıktan sonra a.x, a.y.z ve a.y === b.y ne olur? Aynısını structuredClone ile dene ve farkı açıkla.

★★☆ const stock = { pen: 40, notebook: 0, eraser: 12, ruler: 0 }; object'ini Object.entries ve bir döngüyle gez; stoğu biten ürünlerin adlarını bir array'de topla ve join(", ") ile yazdır.

★★★ Bir cart object'i yaz: içinde bir items array'i, ürün ekleyen bir add method'u ve toplam tutarı döndüren bir getTotal method'u olsun. Method'ların içinde this.items kullan. İki ürün ekle, toplamı yazdır.

Object'ler artık elinde. Peki bu object'i sunucuya göndermek, tarayıcıda saklamak ya da başka bir uygulamayla paylaşmak istersen? Bir sonraki yazıda verinin web'deki ortak dili olan JSON'a geçiyoruz: object'i metne, metni tekrar object'e çevirmeyi ve bu sırada nelerin sessizce kaybolduğunu göreceğiz.