Diyelim ki karmaÅık bir yapı var, bunu karakter dizisine çevirip aÄ Ã¼zerinden loglanması için baÅka bir yere iletilmek isteniyor.
DoÄal olarak, bu karakter dizisi tüm önemli özellikleri içermeli
Bu çevirim Åu Åekilde yapılabilir:
let kullanici = {
adi: "Ahmet",
yasi: 30,
toString() {
return `{adi: "${this.adi}", yasi: ${this.yasi}}`;
}
};
alert(kullanici); // {adi: "Ahmet", yasi: 30}
⦠Fakat geliÅtirme esnasında yeni özellikler eklendi ve öncekiler ya silindi ya da isim deÄiÅtirdi. Böyle bir durumda toString metoduyla her zaman deÄiÅiklik yapmak oldukça zordur. Ãzellikleri döngüye sokup buradan deÄerler alınabilir. Bu durumda da iç içe objelere ne olacak? Bunlarında çevirimlerini yapmak gerekir. Ayrıca aÄ Ã¼zerinden objeyi göndermeye çalıÅtıÄınızda ayrıca bu objenin alan yer tarafından nasıl okunacaÄına dair bilgi göndermek zorundasınız.
Neyse ki bunların hiçbiri için kod yazmaya gerek yok. Bu problem bizim için çözülmüŠdurumda.
JSON.stringify
JSON (JavaScript Object Notation) genelde objelerin deÄerlerini ifade eder.RFC 4627 standardında tanımı yapılmıÅtır. Ãncelikle JavaScript düÅünülerek yapılmıŠolsa da birçok dil de kendine has kütüphanelerle JSON desteÄi vermektedir. Böylece client JavaScript kullanırken server Ruby/PHP/Java/Her neyse⦠kullansa bile JSON kullanımında bir sorun oluÅturmaz.
JavaScript aÅaÄıdaki metodları destekler:
JSON.stringifyobjeyi JSONâa çevirir.JSON.parseJSONâdan objeye çevirmeye yarar.
ÃrneÄin, aÅaÄıda JSON.stringify metodu ögrenci objesi için kullanılmıÅtır:
let ogrenci = {
adi: 'Ahmet',
yasi: 30,
adminMi: false,
dersler: ['html', 'css', 'js'],
esi: null
};
let json = JSON.stringify(ogrenci);
alert(typeof json); // string dönecektir.!
alert(json);
/* JSON'a çevirilmiŠobje:
{
"adi": 'Ahmet',
"yasi": 30,
"adminMi": false,
"dersler": ['html', 'css', 'js'],
"esi": null
}
*/
JSON.stringify(ogrenci) metodu objeyi alır ve bunu karaktere çevirir, buna Json-kodlanmıŠ, seri hale getirilmiÅ veya karakter haline getirilmiÅ denir. Bunu aÄ Ã¼zerinden karÅı tarafa göndermek veya basit bir Åekilde kaydetmek mümkündür.
JSON kodlanmıŠobjenin normal obje ile arasında birkaç tane önemli farklılık vardır:
- Karakterler çift tırnak kullanır. JSONâda tek tırnak veya ters tırnak kullanılmaz. Bundan dolayı
'Ahmet'â"Ahmet"olur. - Obje özelliklerinin isimleri de çift tırnak içinde alınır. Bu da zorunludur. Bundan dolayı
yas:30,"yas":30olur.
JSON.stringify ilkel tiplere de uygulanabilir.
Desteklenen JSON tipleri:
- Objeler
{ ... } - Diziler
[ ... ] - İlkel Tipler:
- karakterler,
- sayılar,
- boolean deÄerler
true/false, null.
ÃrneÄin:
// normal bir sayı JSON için de normal bir sayıdır.
alert( JSON.stringify(1) ) // 1
// karakterler de JSON içinde karakterdir fakat çift tırnak içinde gösterilir.
alert( JSON.stringify('test') ) // "test"
alert( JSON.stringify(true) ); // true
alert( JSON.stringify([1, 2, 3]) ); // [1,2,3]
JSON sadece veriyi tanımlayan diller arası bir Åartname bulunmaktadır. Bundan dolayı JavaScriptâe özel obje özelliklerikleri JSON.stringify tarafından pas geçilir.
Yani:
- Fonksiyon özellikleri ( metodlar ).
- Sembolik özellikler.
undefinedâı saklayan özellikler.
let kullanici = {
merhaba() { // ihmal edilir
alert("Merhaba");
},
[Symbol("id")]: 123, // ihmal edilir
baska: undefined // ihmal edilir
};
alert( JSON.stringify(kullanici) ); // {} (boÅ obje)
Bu özellik kabul edilebilir. EÄer istediÄiniz bu deÄilse, bu iÅlemi nasıl özelleÅtirebilirsiniz bunu göreceksiniz.
Harika olan ise iç içe objeler otomatik olarak çevrilir.
ÃrneÄin:
let tanisma = {
baslik: "Konferans",
oda: {
sayi: 123,
katilimcilar: ["ahmet", "mehmet"]
}
};
alert( JSON.stringify(tanisma) );
/* tüm yapı karakter Åekline çevrildi:
{
"tanisma":"baslik",
"oda":{"sayi":23,"katilimcilar":["ahmet","mehmet"]},
}
*/
Ãnemli bir sınırlama: Dairesel referans olmamalıdır.
ÃrneÄin:
let oda = {
sayi: 23
};
let tanisma = {
baslik: "Konferans",
katilimcilar: ["ahmet", "mehmet"]
};
tanisma.yeri = oda; // tanisma odaya referans veriyor.
oda.dolduruldu = tanisma; // oda tanismaya referans veriyor
JSON.stringify(tanisma); // Hata: Dairesel yapı JSON'a çevrilememiÅtir.
Ãeviri yapılırken hata olmasının nedeni: oda.dolduruldu tanismaâya referans olurken, tanisma.yeri odaâya referans verir.
Hariç tutmak ve dönüÅtürmek: yer deÄiÅtirici ( replacer )
JSON.stringfyâın tam yazımı:
let json = JSON.stringify(deger[, degistirici, bosluk])
- deger
- Kodlanacak metin.
- degistirici
- Mapleme (haritalama) fonksiyonu (
function(key,value)) veya kodlanacak özelliklerin dizisi. - boÅluk
- Formatlanmak için kullanılacak boÅluk.
ÃoÄu zaman JSON.stringifyâın sadece ilk argümanı kullanılır. Fakat daha derinlemesine bir deÄiÅtirici iÅlemi yapmak istiyorsanız. ÃrneÄin dairesel referansı filtrelemek gibi, JSON.stringifyâın diÄer argümanlarını da kullanabilirsiniz.
EÄer üçüncü parametreyi de gönderirseniz, sadece gönderdiÄiniz özellikler kodlanacaktır.
ÃrneÄin:
let oda = {
sayi: 23
};
let tanisma = {
baslik: "Konferans",
katilimcilar: [{adi: "Ahmet"}, {adi: "Mehmet"}],
yer: oda // tanıÅma odayı referans gösteriyor.
};
oda.dolduruldu = tanisma; // oda tanıÅmayı referans gösteriyor.
alert( JSON.stringify(tanisma, ['baslik', 'katilimcilar']) );
// {"baslik":"Konferans","katilimcilar":[{},{}]}
Burada çok sıkı kullandık. Ãzellik listesi tüm yapı için kullanıldı. Bundan dolayı katılımcılar boÅ döndür, adi alanı da istenseydi bu durumda deÄer gelecekti.
Dairesel referansa neden olabilecek oda.dolduruldu hariç hepsini içermek isterseniz:
let oda = {
sayi: 23
};
let tanisma = {
baslik: "Konferans",
katilimcilar: [{adi: "Ahmet"}, {adi: "Mehmet"}],
yer: oda // tanıÅma odayı referans gösteriyor.
};
oda.dolduruldu = tanisma; // oda tanıÅmayı referans gösteriyor.
alert( JSON.stringify(tanisma, ['baslik', 'katilimcilar', 'yer', 'adi', 'sayi']) );
/*
{
"baslik":"Konferans",
"katilimcilar":[{"adi":"Ahmet"},{"adi":"Mehmet"}],
"yer":{"sayi":23}
}
*/
Åimdi ise dolduruldu hariç her yer seri haline getirildi. Fakat özelliklerin listesi oldukça büyük oldu.
Neyse ki degistirici yerine fonksiyon kullanılabilir.
Bu fonksiyon her (anahtar, deger) ikilisi için çaÄırılabilir ve âdeÄiÅtirilmiÅâ deÄeri çevirir, bu da orijinalinin yerine geçer.
Daha önce yaptıÄımız örnekte dolduruldu özelliÄi hariç diÄer özelliklerin degerâin olduÄu gibi kullanılabilir. dolduruldu özelliÄini pas geçmek için aÅaÄıdaki kod undefined döndürür.
let oda = {
sayi: 23
};
let tanisma = {
baslik: "Konferans",
katilimcilar: [{adi: "Ahmet"}, {adi: "Mehmet"}],
yer: oda // tanıÅma odayı referans gösteriyor.
};
oda.dolduruldu = tanisma; // oda tanıÅmayı referans gösteriyor
alert( JSON.stringify(tanisma, function degistirici(anahtar, deger) {
alert(`${anahtar}: ${deger}`); // degistiriciye gelen
return (anahtar == 'dolduruldu') ? undefined : deger;
}));
/* degistiriciye gelen anahtar:deger çifti:
: [object Object]
baslik: Conference
katilimci: [object Object],[object Object]
0: [object Object]
adi: Ahmet
1: [object Object]
adi: Mehmet
yer: [object Object]
sayi: 23
*/
degistirici fonksiyonu iç içe objeler ve diziler dahil her Åeyi alır. Tüm objelere yinelemeli olarak uygulanır. thisâin deÄeri degistirici içerisinde o anki özellikleri tutar.
İlk çaÄrı özeldir. âSarıcı objeâ vasıtasıyla: {"": tanisma}. DiÄer bir deyiÅle ilk (anahtar, deger) çifti boÅ anahtar ile gelir ve deÄeri hedef objenin tamamıdır. Bundan dolayı yukarıdaki örnekte ilk satır: ":[object Object]"'dir.
Fikir degistiriciâyi olabildiÄince güçlü yapmaktır: Böylece gelen tüm objeyi pas geçme veya analiz etme gibi imkanlar saÄlanır.
Formatlama: bosluk
JSON.stringify(deger, degistirici, boÅluk)'ın 3. argümanı formatlamayı güzel yapmak için kaç boÅluk bırakılması gerektiÄi bilgisini alır.
Ãnceden, karakter dizisi haline getirilmiÅ objelerin hiç boÅlukları bulunmamaktaydı. EÄer bunu obje üzerinden göndermek istiyorsanız pek önemli deÄildir. bosluk sadece güzel çıktı vermek amacıyla kullanılır.
Burada bosluk = 2 kullanılmıÅtır, iç içe objelerin birkaç satırda ve objeler arasında 2 boÅluk olacak Åekilde ayarlamasını söyler.
let kullanici = {
adi: "Ahmet",
yas: 25,
roller: {
admin: false,
editor: true
}
};
alert(JSON.stringify(kullanici, null, 2));
/* iki boÅluk:
{
"adi": "Ahmet",
"yasi": 25,
"roller": {
"admin": false,
"editor": true
}
}
*/
/* JSON.stringify(user, null, 4) için ise çıktı aÅaÄıdaki gibi olur:
{
"adi": "Ahmet",
"yasi": 25,
"roller": {
"admin": false,
"editor": true
}
}
*/
bosluk genelde loglama veya güzel çıktı almak için kullanılır.
İsteÄe göre uyarlanmıŠâtoJSONâ
Karakterlerin çeviriminde toString metodunun kullanılabileceÄini daha önce söylemiÅtik. Objeler için toJSON metodu varsa JSON.stringify çaÄırıldıÄında bu otomatik olarak çaÄırılır.
ÃrneÄin:
let oda = {
sayi: 23
};
let toplanti = {
baslik: "Konferans",
tarih: new Date(Date.UTC(2017, 0, 1)),
oda
};
alert( JSON.stringify(toplanti) );
/*
{
"baslik":"Konferans",
"tarih":"2017-01-01T00:00:00.000Z", // (1)
"oda": {"sayi":23} // (2)
}
*/
GördüÄünüz gibi date (1) karaktere dönüÅtü. Bunun nedeni date objesinin toJSON metoduna sahip olmasıdır.
EÄer toJSON metodunu oda objesine uygularsanız:
let oda = {
sayi: 23,
toJSON() {
return this.sayi;
}
};
let toplanti = {
baslik: "Konferans",
oda
};
alert( JSON.stringify(oda) ); // 23
alert( JSON.stringify(toplanti) );
/*
{
"baslik":"Konferans",
"oda": 23
}
*/
GördüÄünüz gibi toJSON hem doÄrudan çaÄrı için hem de iç içe objeler için kullanılabilir.
JSON.parse
JSON-karakterinin kodlamasını geri çevirmek için ( decode ), JSON.parse adında diÄer bir metoda ihtiyaç vardır.
Yazımı:
let deger = JSON.parse(str[, alıcı]);
- str
- Ãözülecek JSON metni.
- alıcı
- Opsiyonel function(anahtar,deger) ile her
(anahtar,deger)çifti için çaÄrılacaktır. Bu deÄerler fonksiyon içerisinde deÄiÅtirilebilir.
ÃrneÄin:
// metne çevrilmiŠdizi
let sayilar = "[0, 1, 2, 3]";
sayilar = JSON.parse(sayilar);
alert( sayilar[1] ); // 1
İç içe objeler için:
let kullanici = '{ "adi": "Ahmet", "yasi": 35, "admin": false, "arkadaslar": [0,1,2,3] }';
kullanici = JSON.parse(kullanici);
alert( kullanici.arkadaslar[1] ); // 1
JSON gerektiÄi kadar karmaÅık olabilir, içerisinde objeler diziler ve bu objelerin içerisinde objeler diziler olabilir. Tek yapması gereken formata uymaktır.
AÅaÄıda elle yazılan JSONâda en çok karÅılaÅılan hatalar sıralanmıÅtır. (Bazen test etme amaçlı elle JSON yazılabilir)
let json = `{
adi: "Ahmet", // hata: İki tırnak olmadan anahtar yazmak
"soyadi": 'Güngör', // hata: DeÄerde tek tırnak kıllanılmıÅtır. Bu çift tırnak olmalı
'admin': false // hata: Anahtar için tek tırnak kullanılmıÅtır.
"dogumGunu": new Date(2000, 2, 3), // hata: "new" deÄeri kabul edilmez, sadece deÄer girilmelidir.
"friends": [0,1,2,3] // hata yok!
}`;
Bunun yanında JSON yorumlara izin vermez. Yorum eklenirse JSON çalıÅmaz hale gelir.
JSON5 adında farklı bir format bulunmaktadır. Bu format tırnaksız yazıma ve yorumlara izin vermektedir. Fakat bu ayrı bir kütüphanedir ve JSONâun Åartnamesinde bulunmamaktadır.
JSONâun daha sıkı yazıma sahip olmasının nedeni geliÅtiricilerinin tembel olması vs deÄildir. Asıl amaç çok daha hızlı ayrıÅtırma algoritması uygulayabilmektir.
Alıcı kullanma
Diyelim ki sunucunuzda tanisma diye bir objeyi metin Åeklinde tutuyorsunuz.
AÅaÄıdaki gibi görünecektir:
// baslik: (tanisma basligi), tarih: (tanisma tarihi)
let str = '{"baslik":"Konferans","tarih":"2017-11-30T12:00:00.000Z"}';
⦠Åimdi bunun tekrar obje haline getirilmesi gerekmektedir. ( deserialize )
JSON.parse kullanarak yapıldıÄından:
let str = '{"baslik":"Konferans","tarih":"2017-11-30T12:00:00.000Z"}';
let tanisma = JSON.parse(str);
alert( tanisma.date.getDate() ); // Hata!
HATA!
tanisma.tarih karakter dizisidir, tarih deÄil. JSON.parse bu karakter dizisini Date objesine çevireceÄini nasıl bilebilir ?
Bunu Alıcı fonksiyon ile tüm deÄerler olduÄu gibi alıp sadece tarih Date objesi olarak çevrilebilir.
let str = '{"baslik":"Konferans","tarih":"2017-11-30T12:00:00.000Z"}';
let tanisma = JSON.parse(str, function(anahtar, deger) {
if (anahtar == 'tarih') return new Date(deger);
return deger;
});
alert( tanisma.tarih.getDate() ); // Åimdi çalıÅıyor!
Bu iç içe objeler için de aynı Åekilde çalıÅır:
let program = `{
"tanismalar": [
{"baslik":"Konferans","tarih":"2017-11-30T12:00:00.000Z"},
{"baslik":"DogumGunu","tarih":"2017-04-18T12:00:00.000Z"}
]
}`;
program = JSON.parse(program, function(anahtar, deger) {
if (anahtar == 'tarih') return new Date(deger);
return deger;
});
alert( program.tanismalar[1].tarih.getDate() ); // çalıÅır!
Ãzet
- JSON kendine ait standardı olan ve birçok programlama dilinde kütüphanesi olan bir veri formatıdır.
- JSON basit objeleri, dizileri, karakterleri, sayıları, boolean deÄerleri ve
nullâu destekler. - JavaScript objeleri seri hale getirmek için JSON.stringify metodunu ve tekrar obje haline getirmek için JSON.parse metodunu saÄlar.
- Her iki metod da çevirilerde kendinize ait fonksiyonlar kullanmanıza olanak verir.
- EÄer obje
toJSONmetoduna sahipse,JSON.stringifysırasında bu metod kullanılır.
Yorumlar
<code>kullanınız, birkaç satır eklemek için ise<pre>kullanın. EÄer 10 satırdan fazla kod ekleyecekseniz plnkr kullanabilirsiniz)