En uzun süre, bir JavaScript değerinin derin bir kopyasını oluşturmak için geçici çözümlere ve kitaplıklara başvurmak zorunda kaldınız. Platform şimdi ile birlikte gelir structuredClone()
derinlemesine kopyalama için yerleşik bir işlev.
- Chrome 98, Desteklenir 98
- Firefox 94, Desteklenir 94
- Kenar 98, Desteklenen 98
- Safari 15.4, Desteklenir 15.4
Sığ kopyalar #
JavaScript’te bir değeri kopyalamak neredeyse her zaman sığaksine derin. Bu, derinlemesine iç içe geçmiş değerlerde yapılan değişikliklerin orijinalde olduğu gibi kopyada da görüleceği anlamına gelir.
kullanarak JavaScript’te sığ bir kopya oluşturmanın bir yolu nesne yayma operatörü ...
:
const myOriginal = {
someProp: "with a string value",
anotherProp: {
withAnotherProp: 1,
andAnotherProp: true
}
};const myShallowCopy = {...myOriginal};
Doğrudan sığ kopyaya bir özellik eklemek veya değiştirmek, orijinali değil yalnızca kopyayı etkiler:
myShallowCopy.aNewProp = "a new value";
console.log(myOriginal.aNewProp)
// ^ logs `undefined`
Ancak, derinlemesine iç içe geçmiş bir özellik eklemek veya değiştirmek, ikisi birden kopya ve orijinal:
myShallowCopy.anotherProp.aNewProp = "a new value";
console.log(myOriginal.anotherProp.aNewProp)
// ^ logs `a new value`
İfade {...myOriginal}
(numaralandırılabilir) özellikleri üzerinde yinelenir myOriginal
kullanmak Yayılma Operatörü. Özellik adını ve değerini kullanır ve bunları yeni oluşturulmuş, boş bir nesneye teker teker atar. Bu nedenle, ortaya çıkan nesne şekil olarak aynıdır, ancak özellikler ve değerler listesinin kendi kopyasına sahiptir. Değerler de kopyalanır, ancak sözde ilkel değerler, JavaScript değeri tarafından ilkel olmayan değerlerden farklı şekilde işlenir. Alıntılamak MDN:
JavaScript’te, bir ilkel (ilkel değer, ilkel veri türü), nesne olmayan ve yöntemi olmayan verilerdir. Yedi ilkel veri türü vardır: string, number, bigint, boolean, undefined, symbol ve null.
MDN — İlkel
İlkel olmayan değerler şu şekilde ele alınır: Referanslardeğeri kopyalama eyleminin gerçekten sadece aynı temel nesneye bir referansı kopyalamak olduğu ve sığ kopyalama davranışıyla sonuçlandığı anlamına gelir.
Derin kopyalar #
Sığ bir kopyanın tersi, derin bir kopyadır. Bir derin kopya algoritması ayrıca bir nesnenin özelliklerini birer birer kopyalar, ancak başka bir nesneye bir referans bulduğunda tekrarlı olarak kendisini çağırır ve o nesnenin de bir kopyasını oluşturur. Bu, iki kod parçasının yanlışlıkla bir nesneyi paylaşmamasını ve bilmeden birbirlerinin durumunu değiştirmemesini sağlamak için çok önemli olabilir.
JavaScript’te bir değerin derin kopyasını oluşturmanın kolay veya güzel bir yolu yoktu. Birçok kişi, aşağıdakiler gibi üçüncü taraf kitaplıklara güveniyordu: Lodash’ın cloneDeep()
işlev. Muhtemelen bu sorunun en yaygın çözümü JSON tabanlı bir hack idi:
const myDeepCopy = JSON.parse(JSON.stringify(myOriginal));
Aslında, bu o kadar popüler bir geçici çözümdü ki, V8 agresif bir şekilde optimize edildi JSON.parse()
ve mümkün olduğu kadar hızlı hale getirmek için özellikle yukarıdaki model. Ve hızlı olmasına rağmen, birkaç eksiklik ve tuzak teli ile birlikte gelir:
- Özyinelemeli veri yapıları:
JSON.stringify()
özyinelemeli bir veri yapısı verdiğinizde atar. Bu, bağlantılı listeler veya ağaçlarla çalışırken kolayca gerçekleşebilir. - Yerleşik tipler:
JSON.stringify()
değer gibi diğer JS yerleşiklerini içeriyorsa atarMap
,Set
,Date
,RegExp
veyaArrayBuffer
. - Fonksiyonlar:
JSON.stringify()
işlevleri sessizce atar.
Yapılandırılmış klonlama #
Platformun zaten birkaç yerde JavaScript değerlerinin derin kopyalarını oluşturma yeteneğine ihtiyacı vardı: IndexedDB’de bir JS değeri depolamak, diskte depolanabilmesi ve daha sonra JS değerini geri yüklemek için seri hale getirilebilmesi için bir tür serileştirme gerektirir. Benzer şekilde, aracılığıyla bir Web Çalışanına mesaj göndermek postMessage()
JS değerinin bir JS alanından diğerine aktarılmasını gerektirir. Bunun için kullanılan algoritmaya “Yapılandırılmış Klon” adı verilir ve yakın zamana kadar geliştiriciler tarafından kolayca erişilebilir değildi.
Bu artık değişti! HTML özelliği, adlı bir işlevi ortaya çıkarmak için değiştirildi. structuredClone()
bu, geliştiricilerin JavaScript değerlerinin derin kopyalarını kolayca oluşturması için bir araç olarak tam olarak bu algoritmayı çalıştırır.
const myDeepCopy = structuredClone(myOriginal);
Bu kadar! API’nin tamamı bu. Ayrıntılara daha derin dalmak istiyorsanız, bir göz atın. MDN makalesi.
Özellikler ve sınırlamalar #
Yapılandırılmış klonlama, sistemin birçok (hepsi olmasa da) eksikliğini giderir. JSON.stringify()
teknik. Yapılandırılmış klonlama, döngüsel veri yapılarını işleyebilir, birçok yerleşik veri türünü destekler ve genellikle daha sağlam ve genellikle daha hızlıdır.
Ancak yine de sizi hazırlıksız yakalayabilecek bazı sınırlamaları vardır:
- prototipler: Eğer kullanırsan
structuredClone()
bir sınıf örneğinde, yapılandırılmış klonlama nesnenin prototip zincirini attığından, dönüş değeri olarak düz bir nesne alırsınız. - Fonksiyonlar: Nesneniz işlevler içeriyorsa, bunlar sessizce atılan.
- klonlanamayanlar: Bazı değerler klonlanabilir yapıda değildir, özellikle
Error
ve DOM düğümleri. neden olacakstructuredClone()
atmak
Bu sınırlamalardan herhangi biri kullanım durumunuz için bir anlaşmayı bozarsa, Lodash gibi kitaplıklar, kullanım durumunuza uyan veya uymayan diğer derin klonlama algoritmalarının özel uygulamalarını sağlamaya devam eder.
Verim #
Henüz yeni bir mikro kıyaslama karşılaştırması yapmamış olsam da, 2018’in başlarında bir karşılaştırma yaptımönce structuredClone()
maruz kaldı. O zamanlar, JSON.parse()
çok küçük nesneler için en hızlı seçenekti. Bunun aynı kalmasını bekliyorum. Yapılandırılmış klonlamaya dayanan teknikler, daha büyük nesneler için (önemli ölçüde) daha hızlıydı. dikkate alındığında, yeni structuredClone()
diğer API’leri kötüye kullanma ek yükü olmadan gelir ve daha sağlamdır JSON.parse()
Derin kopyalar oluşturmak için bunu varsayılan yaklaşımınız yapmanızı tavsiye ederim.
Çözüm #
JS’de bir değerin derin bir kopyasını oluşturmanız gerekiyorsa (belki bunun nedeni değişmez veri yapıları kullanmanız veya bir işlevin bir nesneyi orijinali etkilemeden değiştirebileceğinden emin olmak istemeniz olabilir) artık geçici çözümlere veya kitaplıklar. JS ekosistemi artık structuredClone()
. Huzzah.