Değişmezlik, fonksiyonel programlamanın temel bir prensibidir ve nesne tabanlı programlara da sunacağı çok şey vardır. Değişebilir bir nesne, oluşturulduktan sonra durumu değiştirilebilen bir nesnedir. Değişmez bir nesne, oluşturulduktan sonra durumu değiştirilemeyen bir nesnedir.
JavaScript'te değişmez bir nesneye örnek nedir?
JavaScript'te bazı yerleşik tipler (sayılar, dizeler) değişmezdir, ancak özel nesneler genellikle değişebilir.
Bazı yerleşik değişmez JavaScript nesneleri Math, Date'dir.
Düz JavaScript nesnelerine değişmezlik eklemenin/simüle etmenin birkaç yolu şunlardır.
Nesne Sabit Özellikleri
writable: false ve configurable: false'ı birleştirerek, esasen bir nesne özelliği olarak bir sabit (değiştirilemez, yeniden tanımlanamaz veya silinemez) oluşturabilirsiniz, örneğin:
let myObject = {};
Object.defineProperty(myObject, 'number', {
value: 42,
writable: false,
configurable: false,
});
console.log(myObject.number); // 42
myObject.number = 43;
console.log(myObject.number); // 42
Uzantıları Engelle
Bir nesnenin yeni özellikler eklenmesini engellemek, ancak nesnenin diğer özelliklerini olduğu gibi bırakmak istiyorsanız, Object.preventExtensions(...)'i çağırın:
var myObject = {
a: 2,
};
Object.preventExtensions(myObject);
myObject.b = 3;
myObject.b; // undefined
Katı olmayan modda, b'nin oluşturulması sessizce başarısız olur. Katı modda ise bir TypeError fırlatır.
Mühürle
Object.seal() "mühürlü" bir nesne oluşturur, bu da mevcut bir nesneyi alır ve esasen üzerinde Object.preventExtensions() çağırır, ancak aynı zamanda tüm mevcut özelliklerini configurable: false olarak işaretler.
Dolayısıyla, artık yeni özellikler ekleyemezsiniz, aynı zamanda mevcut hiçbir özelliği yeniden yapılandıramaz veya silemezsiniz (ancak değerlerini yine de değiştirebilirsiniz).
Dondur
Object.freeze() dondurulmuş bir nesne oluşturur, bu da mevcut bir nesneyi alır ve esasen üzerinde Object.seal() çağırır, ancak aynı zamanda tüm "veri erişimci" özelliklerini writable: false olarak işaretler, böylece değerleri değiştirilemez.
Bu yaklaşım, bir nesnenin kendisi için elde edebileceğiniz en yüksek değişmezlik seviyesidir, çünkü nesnede veya doğrudan özelliklerinde herhangi bir değişikliği engeller (ancak yukarıda belirtildiği gibi, başvurulan diğer nesnelerin içeriği etkilenmez).
var immutable = Object.freeze({});
Bir nesneyi dondurmak, nesneye yeni özellikler eklenmesine izin vermez ve mevcut özelliklerin kaldırılmasını veya değiştirilmesini engeller. Object.freeze() nesnenin numaralandırılabilirliğini, yapılandırılabilirliğini, yazılabilirliğini ve prototipini korur. Geçirilen nesneyi döndürür ve dondurulmuş bir kopyasını oluşturmaz.
Değişmezliğin artıları ve eksileri nelerdir?
Artıları
- Daha kolay değişiklik algılama - Nesne eşitliği, referans eşitliği aracılığıyla performanslı ve kolay bir şekilde belirlenebilir. Bu, React ve Redux'ta nesne farklılıklarını karşılaştırmak için kullanışlıdır.
- Değişmez nesnelerle programları düşünmek daha az karmaşıktır, çünkü bir nesnenin zamanla nasıl gelişebileceği konusunda endişelenmenize gerek yoktur.
- Değişmez nesneler fonksiyonlardan döndürüldüğünde veya fonksiyonlara geçirildiğinde savunmacı kopyalar artık gerekli değildir, çünkü değişmez bir nesnenin onun tarafından değiştirilme olasılığı yoktur.
- Referanslar aracılığıyla kolay paylaşım - Bir nesnenin bir kopyası diğer bir kopyası kadar iyidir, bu nedenle nesneleri önbelleğe alabilir veya aynı nesneyi birden çok kez yeniden kullanabilirsiniz.
- İş parçacığı güvenli - Değişmez nesneler, çok iş parçacıklı bir ortamda iş parçacıkları arasında güvenle kullanılabilir, çünkü diğer eşzamanlı çalışan iş parçacıklarında değiştirilme riski yoktur.
- ImmutableJS gibi kütüphaneleri kullanarak, nesneler yapısal paylaşım kullanılarak değiştirilir ve benzer yapılara sahip birden çok nesne için daha az bellek gerekir.
Eksileri
- Değişmez veri yapılarının ve işlemlerinin saf uygulamaları, her seferinde yeni nesneler oluşturulduğu için son derece zayıf performansa neden olabilir. Yapısal paylaşımı kullanan verimli değişmez veri yapıları ve işlemleri için kütüphanelerin kullanılması önerilir.
- Mevcut olanları değiştirmek yerine birçok küçük nesnenin tahsis edilmesi (ve serbest bırakılması) bir performans etkisine neden olabilir. Ayırıcı veya çöp toplayıcının karmaşıklığı genellikle yığında bulunan nesne sayısına bağlıdır.
- Grafikler gibi döngüsel veri yapılarını oluşturmak zordur. Başlatmadan sonra değiştirilemeyen iki nesneniz varsa, onları birbirlerini gösterecek şekilde nasıl ayarlarsınız?
Kendi kodunuzda değişmezliği nasıl sağlayabilirsiniz?
Alternatif olarak, yukarıda belirtilen oluşturma teknikleriyle birlikte const bildirimlerini kullanmaktır. Nesneleri "değiştirmek" için, orijinal nesneyi değiştirmek yerine yeni nesneler oluşturmak için yayılma operatörünü, Object.assign'i, Array.concat()'ı vb. kullanın.
Örnekler:
// Dizi Örneği
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // [1, 2, 3, 4]
// Nesne Örneği
const human = Object.freeze({ race: 'human' });
const john = { ...human, name: 'John' }; // {race: "human", name: "John"}
const alienJohn = { ...john, race: 'alien' }; // {race: "alien", name: "John"}