Size Saatler Kazandıracak 7 JSON Hilesi
Her JavaScript geliştiricisi haftada onlarca kez JSON.parse ve JSON.stringify kullanır. Ancak çoğu temellerde kalır — API yanıtlarını ayrıştırma ve nesneleri dizgilere seri hale getirme. API'nin sunacak daha çok şeyi var ve daha az kullanılan bazı özellikler, aksi takdirde üçüncü taraf kütüphaneler veya saatlerce hata ayıklama gerektirecek sorunları çözüyor.
Bu kılavuz, varsayılanların ötesine geçen yedi hileyi ele alır. Her biri gerçek kod tabanlarına anında uygulanabilir. Soyutlama yok, uydurma örnekler yok — bunlar üretim sistemlerinde karşılaşılan desenlerdir.
Bu makaledeki kod örneklerinden herhangi birini, tamamen tarayıcınızda JSON'u doğrulayan ve güzel yazdıran Toova JSON Formatter'ı kullanarak doğrulayabilir ve keşfedebilirsiniz.
1. JSON Gidiş-Dönüşü ile Derin Klon (ve Sınırları)
JavaScript oyun kitabındaki en eski hile: düz bir nesnenin derin klonunu oluşturmak için JSON.parse(JSON.stringify(obj)) kullanın.
const original = { a: 1, b: { c: 2 } };
// Naif yaklaşım — derinlemesine iç içe nesneler hâlâ paylaşılır
const shallowCopy = { ...original }; // b hâlâ aynı nesneye işaret eder
// JSON derin klon — tamamen bağımsız bir kopya oluşturur
const deepClone = JSON.parse(JSON.stringify(original));
deepClone.b.c = 99;
console.log(original.b.c); // 2 — orijinal dokunulmadan kalır Bu, bir dizgiye seri hale getirme ve geri ayrıştırmanın paylaşılan başvuru olmayan tamamen yeni bir nesne ağacı oluşturması nedeniyle çalışır. Hızlıdır, bağımlılık gerektirmez ve ES5'ten beri mevcuttur.
Bellek içi kullanım için modern alternatif structuredClone()'dur:
// Modern alternatif: structuredClone() — daha fazla türü ele alır
// Node.js 17+ ve tüm sürekli güncellenen tarayıcılarda desteklenir
const clone = structuredClone(original); Buna güvenmeden önce JSON yaklaşımının sınırlarını bilin:
// JSON.parse/stringify ŞUNLARI ele ALAMAZ:
const broken = {
date: new Date(), // dizgiye dönüşür — Date prototipini kaybeder
fn: () => 'hello', // sessizce düşürülür
undef: undefined, // sessizce düşürülür
inf: Infinity, // null olur
map: new Map(), // {} olur
cycle: null, // dairesel başvurular hata fırlatır
};
Nesneniz yalnızca düz veri içeriyorsa — dizgiler, sayılar, boolean'lar, diziler ve iç içe düz nesneler — JSON gidiş-dönüşü güvenli ve hızlıdır. Diğer her şey için structuredClone() veya özel bir kütüphane tercih edin.
2. Filtreleme ve Maskeleme için Özel Replacer
Çoğu geliştirici JSON.stringify'ın ikinci argüman aldığını bilir ancak nadiren kullanır. Bu ikinci argüman replacer'dır: ya dahil edilecek anahtarların bir dizisi ya da her değerin tam olarak nasıl seri hale getirileceğini kontrol eden bir fonksiyon.
Dizi replacer — belirli anahtarları beyaz listeye al:
const user = {
id: 'u_001',
name: 'Alice',
password: 'hunter2', // loglarda görünmemeli
creditCard: '4111111111111111', // loglarda görünmemeli
role: 'admin',
};
// Replacer dizi olarak: yalnızca bu anahtarları dahil et
JSON.stringify(user, ['id', 'name', 'role']);
// '{"id":"u_001","name":"Alice","role":"admin"}' Fonksiyon replacer — değerleri dönüştür veya gizle:
// Replacer fonksiyon olarak: anahtar/değer üzerinde tam kontrol
const masked = JSON.stringify(user, (key, value) => {
if (key === 'password' || key === 'creditCard') return '[REDACTED]';
if (key === '' ) return value; // kök nesne — her zaman döndür
return value;
});
// '{"id":"u_001","name":"Alice","password":"[REDACTED]","creditCard":"[REDACTED]","role":"admin"}' Daha sofistike bir sürüm, anahtar adı yerine şekillerine göre değerleri maskeler:
// Tür tabanlı maskeleme için replacer
const sanitize = (key, value) => {
if (typeof value === 'string' && value.match(/^4[0-9]{15}$/)) {
return '****-****-****-' + value.slice(-4);
}
return value;
}; Bu teknik, loglama middleware'i için vazgeçilmezdir: tam nesne bağlamıyla yapılandırılmış log'lar istersiniz, ancak bazı alanlar asla bir log toplayıcıya ulaşmamalıdır. Replacer, gizleme mantığını kod tabanına dağıtmak yerine seri hale getirme sınırında ele almanıza izin verir.
3. Anahtarları Deterministik Olarak Sırala
JavaScript'te nesne anahtar sırası ekleme sırasıdır (dizgi anahtarları için). Aynı anahtarlara sahip ancak farklı sıralarda oluşturulan iki nesne, farklı JSON dizgileri üretir; bu, naif eşitlik kontrollerini, önbellek anahtarlarını ve içerik karmalarını bozar.
function sortedStringify(obj) {
return JSON.stringify(obj, Object.keys(obj).sort());
}
const a = { z: 1, a: 2, m: 3 };
const b = { a: 2, m: 3, z: 1 };
sortedStringify(a) === sortedStringify(b); // true — anahtar sırası normalize edildi Derinlemesine iç içe nesneler için sıralamayı özyinelemeli olarak uygulayın:
// İç içe nesneler için özyinelemeli anahtar sıralama
function sortKeys(value) {
if (Array.isArray(value)) return value.map(sortKeys);
if (value !== null && typeof value === 'object') {
return Object.fromEntries(
Object.keys(value).sort().map((k) => [k, sortKeys(value[k])])
);
}
return value;
}
const sorted = JSON.stringify(sortKeys(deepNested)); Sıralı JSON şu durumlarda gereklidir:
- İstek gövdelerinden önbellek anahtarları oluşturma
- JSON yüklerinde sağlama toplamları veya imzalar hesaplama
- Alan sırasından bağımsız olarak testlerde API yanıtlarını karşılaştırma
- Sıralamanın eşitliği etkilememesi gereken yapılandırma nesnelerini depolama
Sıraladıktan ve güzel yazdırdıktan sonra, iki normalize edilmiş JSON dizgisini karşılaştırmak ve sürümler arasında tam olarak hangi değerlerin değiştiğini görmek için Text Diff aracını kullanın.
4. Hassasiyet Kaybetmeden BigInt İşleme
JavaScript'in Number türü, 253 − 1'e kadar tamsayıları güvenle temsil edebilir. Dağıtık sistemler tarafından üretilen ID'ler, küçük birimlerdeki finansal tutarlar veya nanosaniyelerdeki zaman damgaları için bu yeterli değildir. BigInt isteğe bağlı hassasiyetli tamsayıları kapsar, ancak JSON.stringify bunlarla ne yapacağını bilmez.
const data = {
amount: 9007199254740993n, // Number.MAX_SAFE_INTEGER'dan büyük
};
// Bu hata fırlatır: TypeError: Do not know how to serialize a BigInt
JSON.stringify(data); // HATA Standart geçici çözümler:
// Çözüm 1: Replacer ile dizgiye dönüştür
JSON.stringify(data, (key, value) =>
typeof value === 'bigint' ? value.toString() : value
);
// '{"amount":"9007199254740993"}'
// Çözüm 2: BigInt prototipinde toJSON() (monkey-patch — dikkatli kullanın)
BigInt.prototype.toJSON = function () { return this.toString(); };
JSON.stringify(data); // '{"amount":"9007199254740993"}' Ayrıştırma tarafında, bir reviver fonksiyonu BigInt değerlerini dizgi temsillerinden geri yükleyebilir:
// Ayrıştırırken BigInt'i geri yüklemek için reviver
const revived = JSON.parse('{"amount":"9007199254740993"}', (key, value) => {
if (key === 'amount') return BigInt(value);
return value;
});
console.log(typeof revived.amount); // 'bigint'
BigInt'ten dizgiye dönüşümü, tutarlı bir şekilde uygulanması için paylaşılan bir seri hale getirme katmanında tutun. BigInt'lerin bir kod tabanının uçlarındaki ad hoc JSON.stringify çağrılarına sızmasına izin vermek, izi sürmesi zor öngörülemez hatalara yol açar.
5. Dairesel Başvuru Algılama
Bir nesne kendisine veya nesne grafiğindeki bir atayına bir başvuru içerdiğinde dairesel bir başvuru oluşur. Düşündüğünüzden daha yaygındırlar: olay yayıcıları, DOM düğümleri, React fiber düğümleri ve ORM varlıklarının hepsinin sıkça geri başvuruları vardır.
// Dairesel başvuru örneği
const obj = { name: 'node' };
obj.self = obj; // obj kendine başvurur
JSON.stringify(obj); // hata fırlatır: TypeError: Converting circular structure to JSON Ziyaret edilen nesneleri izleyen özel bir replacer ile ele alın:
// Manuel dairesel başvuru işleyicisi
function safeStringify(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) return '[Circular]';
seen.add(value);
}
return value;
});
}
safeStringify(obj); // '{"name":"node","self":"[Circular]"}' WeakSet burada doğru veri yapısıdır: çöp toplamayı engellemeden nesne başvuruları tutar ve arama O(1)'dir. Bu desen ayrıca, hataların seri hale getirme sırasında hata fırlatmak yerine zarif bir şekilde bozulmasını istediğiniz loglama middleware'inde de çalışır.
Yaygın bir varyasyon: dairesel başvuruları [Circular] olarak işaretlemek yerine, hata ayıklama sırasında başvuru konumunu açık hale getirmek için [Circular: $.config.parent] gibi bir yol dizgisiyle değiştirin.
6. Dizileri Tek Satırda Güzel Yazdır
JSON.stringify'a üçüncü argüman girintidir. 2 veya 4 geçirmek her şeyi birden çok satıra genişletir; bu nesneler için harikadır ancak etiketler, ID'ler veya koordinatlar gibi ilkel dizileri için ayrıntılı olabilir.
const mixed = {
title: 'Report',
tags: ['json', 'api', 'debug'],
config: { indent: 2, sortKeys: true },
count: 42,
};
// Varsayılan: her şey çok satırlı
JSON.stringify(mixed, null, 2);
// {
// "title": "Report",
// "tags": [
// "json",
// "api",
// "debug"
// ],
// "config": {
// "indent": 2,
// "sortKeys": true
// },
// "count": 42
// } Basit dizileri tek bir satıra daraltmak için çıktıyı son işlemden geçirebilirsiniz:
// Tek satırlı diziler için özel replacer
function prettyMixed(obj) {
const raw = JSON.stringify(obj, null, 2);
// Yalnızca ilkel değerler içeren dizileri tek satıra daralt
return raw.replace(
/\[\n\s+([\s\S]*?)\n\s+\]/g,
(match, inner) => {
const items = inner.split(',\n').map((s) => s.trim());
if (items.every((s) => !/^[{\[]/.test(s))) {
return '[' + items.join(', ') + ']';
}
return match;
}
);
} Sonuç: nesneler okunabilirlik için çok satırlı kalır, ilkel dizileri kompaktlık için tek satıra daralır. Bu, hem insanların hem de makinelerin aynı veriyi okuması gereken birçok yapılandırma dosyasında ve yapılandırılmış log çıktısında kullanılan biçimdir. JSON Formatter ve JSON to YAML dönüştürücüsü bu daralmayı otomatik olarak ele alır.
7. Büyük JSON'u Streaming
Ayrıştırmadan önce büyük bir JSON dosyasını tamamen belleğe yüklemek, JSON işleme hatlarındaki en yaygın performans hatasıdır. 100 MB'lık bir JSON yanıtı, ham dizgi için en az 100 MB heap tahsis eder, ardından ayrıştırılmış nesne için ikinci bir tahsisat yapılır. Birkaç megabaytın üzerindeki dosyalar için, bir streaming ayrıştırıcı veriyi kademeli olarak işler.
Bir streaming kütüphanesiyle Node.js'te:
// node --experimental-vm-modules (veya bir streaming JSON kütüphanesi kullanın)
// JSON Source Map önerisi (Aşama 3, 2026) ile yerel streaming:
// Şimdilik, @streamparser/json veya jsonstream2 gibi bir kütüphane kullanın
import { createReadStream } from 'fs';
import parser from '@streamparser/json';
const jsonParser = new parser.JSONParser();
jsonParser.onValue = ({ value, key, parent }) => {
if (key === 'id') {
console.log('id bulundu:', value);
}
};
createReadStream('large.json').pipe(jsonParser); Fetch Streams API kullanan tarayıcıda:
// Fetch + JSON stream decoder ile tarayıcı tarafı streaming:
const response = await fetch('/api/large-data');
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// Tamponun içinden tam JSON nesnelerini işle...
}
Streaming, toplu işleme hatlarında, büyük dışa aktarma uç noktalarında ve log analiz betiklerinde en yararlıdır. 1 MB'ın altındaki tipik API yanıtları için, standart JSON.parse yeterince hızlıdır ve çok daha basittir. Pratikte streaming'in karşılığını vermeye başladığı eşik, ayrıştırılan yapının karmaşıklığına ve hedef ortamın heap boyutuna bağlı olarak yaklaşık 5–10 MB civarındadır.
Bir streaming ayrıştırıcı oluşturmadan önce büyük JSON yanıtlarının yapısını keşfetmek için, hangi yolların ihtiyacınız olan veriyi içerdiğini görmek üzere bir örneği JSON Formatter'a yapıştırın, ardından daha fazla analiz için CSV veya YAML'a dönüştürün.
Hepsini Bir Araya Getirme
Bu yedi teknik, JSON API'nin en etkili köşelerini kapsar:
- Derin klon gidiş-dönüş yoluyla — düz veri için hızlı, sınırları bilin
- Replacer — seri hale getirme sınırında anahtarları filtreleyin ve hassas değerleri maskeleyin
- Anahtar sıralama — önbellek anahtarları, imzalar ve test iddiaları için deterministik çıktı
- BigInt işleme — dizgiye seri hale getir, ayrıştırırken geri yükle
- Dairesel başvuru algılama — güvenli seri hale getirme için WeakSet tabanlı replacer
- Kompakt dizilerle güzel yazdırma — fazla boşluk olmadan okunabilir çıktı
- Büyük JSON streaming — büyük dosyalar ve API yanıtları için kademeli ayrıştırma
JSON.stringify'ın replacer ve space argümanlarının tam belgeleri için, MDN JSON.stringify referansına bakın. Modern derin klon alternatifi için, tüm desteklenen türleri ve uç durumları kapsayan structuredClone() belgelerine bakın.